我的箭头函数为什么会返回`undefined`?

4

这个问题旨在作为关于将单行/表达式箭头函数体语法与自动返回与多行/块版本混淆所导致的问题的规范重复目标。


我有一个箭头函数用于相加两个数字,但是当我调用它时,它返回undefined。为什么?

const add = (a, b) => {
  a + b
}

console.log(add(1, 2)) // expected: 3, actually: undefined

替代问题:

我的 React 组件应该使用 map 来渲染列表项,但列表始终为空。为什么?

<ul>
  {list.map(item => {
    <li>
      <a href="{item.url}">{item.name}</a>
    </li>
  })}
</ul>

我发誓,我搜索了超过10分钟,也找不到那个dup。谢谢。 - CherryDT
2个回答

5
箭头函数支持两种不同的语法体式:表达式块状体
如果只提供单个表达式(例如a + b)而没有括号{ },则该表达式会自动返回。
const add = (a, b) => a + b

如果提供了由 { } 包围的代码块,则它就像常规的函数体一样工作,并要求使用专用的 return 语句来返回一个值:
const add = (a, b) => {
  return a + b
}

单表达式函数常用于以简洁的方式编写仅执行一个操作或条件的简单函数,如以下示例:

if (users.every(user => user.age >= 18)) { /* ... */ }

const emails = users.map(user => user.email)

const titleCased = string.replace(/\b\w/g, s => s.toUpperCase())

// in the following example, the return value is irrelevant
setTimeout(() => doStuff(1, 2, 3), 1000)

在大多数情况下,特别是当您想在函数体中有多个语句、循环或条件时,使用块。
请注意,即使没有块,如果仍然是单个表达式,则可以拥有跨越多行的函数体。但是,如果您出于可读性原因想将其转换为块,则必须不要忘记添加"return"(除非您的函数不打算返回任何内容)。
现在,这就是为什么您的 "add "函数返回 undefined 的原因——它既没有单表达式体("{ }"使其成为块),也没有在其体中具有任何"return"语句。所以,会计算"a+b",但结果没有用于任何事情——被丢弃并继续执行,到达函数的末尾并返回不带返回值的 undefined,因为没有给出返回值。
在 React 中的情况也是一样的。您嵌入了一个 ".map" 调用的返回值,应该是要呈现的进一步内容的数组,但由于您的回调未返回任何值,因此将项目映射到若干个 "undefined "值,并在最后呈现了 "undefined"。
但这里还有一个小技巧:您可能需要在像 "map" 回调这样的函数中返回元素的多行,但您会发现以下两个选项都不太干净:
<ul>
  {list.map(item => <li>
    <a href="{item.url}">{item.name}</a>
  </li>)}
</ul>

<ul>
  {list.map(item => {
    return <li>
      <a href="{item.url}">{item.name}</a>
    </li>
  })}
</ul>

通常情况下,为了避免使用额外的 return 语句,我们会使用括号( )将表达式括起来。最终仍然是一个单一的表达式,但更易于处理。

<ul>
  {list.map(item => (
    <li>
      <a href="{item.url}">{item.name}</a>
    </li>
  ))}
</ul>

有关箭头函数的更多信息,请参见此处。要了解箭头函数和常规函数之间的其他区别(例如this的不同行为),请参见此处


0
箭头函数在以下情况下返回代码:

情况1:当它像下面这样内联写入时

/* notice that this is an implicit return 
and we don't need a return statement here as the code is 
in the same line after the => */

const add = (a, b) => a + b  
    
console.log(add(1, 2)) // expected: 3

情况2:当它像这样用圆括号()写出来时

情况2 - 示例1

/* notice the round bracket here. 
You will use this when you have a 
block of code here unlike case 1 
where you had a single line to return */

const add = (a, b) => ( // this is round bracket, no return needed 
    a + b 
    // and other blocks of code. Look at the below JSX example for
    // for this case
)

console.log(add(1, 2)) // expected: 3

上述示例类似于第二种情况2 - 示例1,但这种情况更适用于大多数JSX的单个代码块,如下所示

情况2 - 示例2

<ul>
  {list.map(item => ( // this is round bracket, no return needed
    <li>
      <a href="{item.url}">{item.name}</a>
    </li>
  )}
</ul>
情况三:当您像这样使用花括号时,带有显式的return语句
const add3 = (a, b) => { // curly braces + return statement
  return a + b;
};

const res3 = add3(1, 2);

console.log(res3); // 3

在您的情况下,请注意您正在混合使用第2种和第3种情况。也就是说,您正在使用第3种情况中定义的花括号,并且还没有像第2种情况中那样使用返回关键字,这就是它无法工作的原因。
代码:https://codesandbox.io/s/javascript-forked-ckjg69?file=/src/index.js

2
你对第二种情况的解释有点令人困惑,因为你不能在其中放置任何语句或多个表达式的常规“代码块”,它仍然必须是单个表达式。实际上,它与第一种情况相同,只是表达式现在是 ( a + b )。 (你可以使用逗号运算符,但我认为这样会很快变得丑陋。)我还建议将代码注释拆分成多行,因为它们目前有点难以阅读,会导致水平滚动条出现。 - CherryDT
更新了我的回答!如果您需要更多的澄清,请告诉我。 - Sandeep Amarnath

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