JS:Array.map不会添加到数组

13

我有一些数据想要使用Array.prototype.map进行转换。但是在map函数中,外部函数调用可能会抛出错误。我想捕获此错误并不将该特定对象添加到返回的数组中。目前,我只返回undefined,然后使用Array.prototype.filter清除undefined值,但这似乎是一种不太好的方法。

为了澄清,我要实现的功能是:

['apple','pear','banana', 'peach'].map(function(fruit){
     if (fruit === 'apple') {
         return undefined;
     }
     return 'I love to eat ' + fruit;
});
// ['I love to eat pear', 'I love to eat peach', 'I love to eat banana']

有任何现有的实现吗?我是不是走错了方向?


@JamesThorpe,你的链接是指jQuery的.map()方法,而不是Javascript的方法。 - Barmar
6个回答

17

更易读的方式是:

['apple','pear','banana', 'peach'].filter(function(fruit) {
    return fruit === 'apple';
}).map(function(fruit) {
    return 'I love eating ' + fruit; 
})

使用箭头函数和模板字符串;

['apple','pear','banana', 'peach']
    .filter(fruit => fruit === 'apple')
    .map(fruit => `I love eating ${fruit}`)

啊,我更喜欢这种方式。在映射之前使用过滤器可以将操作分成更清晰的部分。谢谢!编辑:@Barmar是对的-虽然这是一种更干净的方式,但它现在不适合我的确切用例。我可能仍会接受它,因为它适用于其他我遇到可读性问题的情况。 - jtmarmon
2
虽然这对他的示例代码有效,但似乎不适用于实际情况。他说他正在调用一个可以报告错误的函数,并且这是他想要过滤掉的情况。 - Barmar
@JasonMarmon 在调用.map()函数之前,你能否检查一下错误? - Barmar
希望这可以帮到你,如果你能提供任何进一步的代码来找出导致错误的原因,我认为我可能能够编辑我的答案! - Renato Gama
如果 OP 正在进行异步外部调用,那么我认为使用 .map.filter 不是正确的方法。如果是这种情况,我建议看一下 async 库 - Renato Gama
显示剩余2条评论

9
如果你不想使用简单的 for 循环,那么可以尝试使用 reduce。代码示例如下:

var result = ['apple','pear','banana', 'peach'].reduce(function(prev, curr){
     if (curr === 'apple') {
         return prev;
     }
     prev.push(curr);
     return prev;
}, []);

alert(result);

因此,在发生“异常”情况下,您只需返回未经修改的prev数组即可。


非常聪明地使用了 reduce。当然,可以修改代码,只有在某些条件为真时才执行 push 操作,从而只留下一个 return prev,但这只是小问题。 - raina77ow
1
这确实是 reduce 的巧妙运用,但在我看来,它并不比过滤更简单理解或更易读。 - jtmarmon
是的,可能可以。然而我个人会选择使用 for/forEach 的方式。 - dfsq
我不同意。这比在Array.prototype中创建另一个方法要好,而且它非常简洁。由于这段代码很可能应该封装在一个单独的函数“模型”中,我真的觉得使用语言提供给我们的东西没有什么问题。 - raina77ow
这段代码片段实际上可以进一步减少。在我看来,如果可能的话,应该始终避免向数组中推送数据。 var result = ['苹果','梨','香蕉','桃子'] .reduce(function(prev, curr){ if (curr === '苹果') { return prev; } return prev.concat(curr); }, []); - user3619165

3

我最终将这两种方法合并到了Array原型中。正如@Benmj所提到的,你也可以将其放在自定义实用库中。

Array.prototype.mapDefinedValues = function(handler) {
  return this.map(function(item){
    return handler(item);
   }).filter(function(item){
    return item !== undefined;
   });
}

在映射之前进行过滤可以在映射之前删除不必要的元素,从而减少您需要映射的元素数量。 - Patrick

2

0

上面的答案甚至可以进一步简化。

实际上,这段代码片段可以进一步简化。在我看来,如果可以避免向数组中添加元素,就应该尽量避免。

var result = ['apple','pear','banana', 'peach'].reduce(function(prev, curr){
   if (curr === 'apple') {
     return prev;
   }
   return prev.concat(curr);
  }, []);

0

正如评论中所述,您应该将其与过滤器结合使用。幸运的是,这很容易,因为您可以链接数组方法:

['apple','pear','banana', 'peach'].map(function(fruit){
     if (fruit === 'apple') {
         return undefined;
     }
     return 'I love to eat ' + fruit;
}).filter(function (item) { return item; });

更新

像这样的函数式编程的原则之一是创建没有副作用的简单构建块。OP所描述的本质上是向.map添加了一个副作用,这种行为应该被反对。


他说这是他目前正在做的事情。 - Barmar
他也这么说。他还说这“感觉很不好”。其实不应该这样 :) - Ben Jacobs
好主意。这就是 map 应该做的事情。相反,我将在 Array.prototype 上实现一个新方法,自动组合这两个方法。 - jtmarmon
1
但是你组合现有函数创建新函数的一般方法完全可靠。 - Ben Jacobs
1
@Benmj @jtmarmon 如果你在其他地方单独定义toSomethingoutUndefined函数,那么 .map(toSomething).filter(outUndefined) 就会更易读 :) - Michahell
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接