【问题标题】:How to make this function more reusable/specific/better design?如何使这个功能更可重用/具体/更好的设计?
【发布时间】:2019-09-05 09:45:18
【问题描述】:

我在下面写了这个函数,它通过产品类型和货币类型转换传递的产品数组

function getProductsByCurrency(products, type, exchangeRate = 1) {
    var productsRetrieved = products.map(item => ({id: item.id,
        name: item.name,
        price: (item.price * exchangeRate).toFixed(2),
        type: type}));
    return productsRetrieved;       
}

是否可以将功能分解为更具体?或以更好的方式设计它? 例如,通过将其命名为 getProductsByCurrency 它看起来不正确,因为如果我以默认汇率使用它,我可以传递书籍数组来检索具有“书籍”类型的产品,而与汇率无关。 或许有办法使用偏函数(FP)?

编辑: 为我想要实现的目标添加更多上下文。

假设我有三类产品(手机、化妆品、书籍) 来自三个资源。我需要创建三个不同货币的所有产品的合并数组(productsinUSD、productsinAUD、productsinPounds)

也使用下面的函数来合并数组

    function concatProducts(arr) {
        return [].concat.apply([], arr);
    }

所以我调用 getProductsByCurrency 三次以按产品类型和货币(汇率)转换它们,并将这些值作为数组传递以将它们连接起来以实现 productsinUSD。并重复以获取以澳元为单位的产品,以英镑为单位的产品。

类型也是字符串值(例如:'mobiles')

【问题讨论】:

  • 不清楚(至少对我来说)你在问什么..
  • 您能否添加 2 个不同的示例来说明您希望如何使用该功能以及各自的结果?
  • 不清楚您是否希望该功能适用​​于更广泛的产品或特定产品。 (更抽象或更不抽象)
  • 添加了更多上下文,希望现在清楚。
  • 您应该始终编写尽可能简单且需要尽可能少上下文的函数。您的getProductsByCurrency 需要Array 的产品,但它应该只需要一个产品。在函数之外进行映射。

标签: javascript arrays functional-programming reusability partial-application


【解决方案1】:

首先,您发布的功能并没有真正错误。有几件事我会做不同的事情,但我不会假装这不会让我有点担心。

const processItem = (type, exchangeRate = 1) => ({
  id,
  price,
  name,
}) => ({
  id,
  name,
  type,
  price: (price * exchangeRate).toFixed(2),
});

我们有一个函数,它接受一个类型和一个可选的 exchangeRate,并返回一个将单个项目转换为您想要的形式的函数。这就是鲍勃在 cmets 中所说的。我还在项目上使用了对象解构,并在结果上使用了属性简写,以使代码更清晰。现在我们可以将它映射到各种类别的东西上:

const results = [
   ...mobilePhones.map(processItem('phone')),
   ...cosmetics.map(processItem('cosmetics')),
   ...books.map(processItem('book')),
];

如果您需要临时结果用于其他目的,只需将它们填充到 vars 中,但为了简单起见,我已将它们直接传播到结果数组中。

虽然这比您发布的代码质量帽子戏法更短、更清晰、更灵活,但我想重申一下,我看到的方式比您发布的功能更糟糕。

【讨论】:

  • 这太完美了!我有点困惑它是如何工作的。当您映射它时,您只传递类型而不传递实际项目?它怎么知道拿走物品?
  • 传入的类型返回一个函数,然后被传递给 map,map 一次将一个项目提供给它。
  • 是的,明白了。谢谢。您不认为在上述解决方案中我们正在失去可读性并且不知道processItem 中实际发生了什么,除非我们去寻找它。如果是这样,有没有办法防止它?
  • 更好的命名会有所帮助:使用 'inventory' 调用类似inventoryTransformerCallbackFactory 的东西可能会被更特定于域的东西所取代。我通常懒得为 SO 答案取好名字:D。
【解决方案2】:

您所做的没有任何问题,但您还可以创建另外 3 个函数来调用它,然后使用相应的类型调用 getProductsByCurrency

var example = JSON.parse(`[{"id":1,"name":"1","price":5},{"id":2,"name":"2","price":15},{"id":3,"name":"3","price":20}]`);

function getProductsByCurrency(type, products, exchangeRate = 1) {
  return products.map(item => ({
    id: item.id,
    name: item.name,
    price: (item.price * exchangeRate).toFixed(2),
    type: type
  }));
}

function getPhonesByCurrency() {
  return getProductsByCurrency("phone", ...arguments);
}

function getCosmeticsByCurrency() {
  return getProductsByCurrency("cosmetic", ...arguments);
}

function getBooksByCurrency() {
  return getProductsByCurrency("book", ...arguments);
}

console.log([].concat(getPhonesByCurrency(example), getCosmeticsByCurrency(example, 0.5), getCosmeticsByCurrency(example, 2)));

您可能还更喜欢将这 3 个函数包装在一个对象中(更整洁并有助于 IDE 自动完成)

var example = JSON.parse(`[{"id":1,"name":"1","price":5},{"id":2,"name":"2","price":15},{"id":3,"name":"3","price":20}]`);

function getProductsByCurrency(type, products, exchangeRate = 1) {
  return products.map(item => ({
    id: item.id,
    name: item.name,
    price: (item.price * exchangeRate).toFixed(2),
    type: type
  }));
}

const getByCurrency = {
  phones: function() {
    return getProductsByCurrency("phone", ...arguments);
  },
  cosmetics: function() {
    return getProductsByCurrency("cosmetic", ...arguments);
  },
  books: function() {
    return getProductsByCurrency("book", ...arguments);
  }
};

console.log([].concat(getByCurrency.phones(example), getByCurrency.cosmetics(example, 0.5), getByCurrency.books(example, 2)));

【讨论】:

    【解决方案3】:

    这取决于您输入这些函数的数据类型。如果您将传递不同的对象数组(它们都具有 type 属性),那么我认为您将拥有一个按类型(或不同数据集之间常见的任何其他属性和条件)过滤数组的函数。您可以将过滤器功能与映射功能链接起来。您的映射函数似乎需要特定于货币,因为您从对象中提取某些道具,而不是在返回之前计算一些值。

    希望对你有帮助

    【讨论】:

    • type 是一个字符串值,如 'mobiles' 、 'books'。应该说得更清楚。所以我认为过滤器在这里不起作用
    猜你喜欢
    • 1970-01-01
    • 2013-10-31
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多