Quando devo usar o `return` no es6 Arrow Functions?

Respostas:

261

Jackson respondeu parcialmente a isso em uma pergunta semelhante:

Retorno implícito, mas apenas se não houver bloqueio.

  • Isso resultará em erros quando um one-liner se expandir para várias linhas e o programador esquecer de adicionar um return.
  • O retorno implícito é sintaticamente ambíguo. (name) => {id: name}retorna o objeto {id: name}... certo? Errado. Retorna undefined. Essas chaves são um bloco explícito. id:é um rótulo.

Eu acrescentaria a isso a definição de um bloco :

Uma instrução de bloco (ou instrução composta em outros idiomas) é usada para agrupar zero ou mais instruções. O bloco é delimitado por um par de colchetes.

Exemplos :

// returns: undefined
// explanation: an empty block with an implicit return
((name) => {})() 

// returns: 'Hi Jess'
// explanation: no block means implicit return
((name) => 'Hi ' + name)('Jess')

// returns: undefined
// explanation: explicit return required inside block, but is missing.
((name) => {'Hi ' + name})('Jess')

// returns: 'Hi Jess'
// explanation: explicit return in block exists
((name) => {return 'Hi ' + name})('Jess') 

// returns: undefined
// explanation: a block containing a single label. No explicit return.
// more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
((name) => {id: name})('Jess') 

// returns: {id: 'Jess'}
// explanation: implicit return of expression ( ) which evaluates to an object
((name) => ({id: name}))('Jess') 

// returns: {id: 'Jess'}
// explanation: explicit return inside block returns object
((name) => {return {id: name}})('Jess') 
Jess Telford
fonte
Eu não entendo essa sintaxe .. você está criando uma classe usando um litoral de classe e depois chamando um construtor implícito com um argumento ('Jess')? Eu pensei que você faria para isso ((nome) => ({id: 'Jess'}))
Michael Dausmann
3
@MichaelDausmann É uma função de seta que possui um parâmetro, namecom a função entre parênteses e invocada com um argumento, "Jess". O código entre =>e )('Jess')em cada caso é o corpo da função de seta. Considere-o como uma forma abreviada de uma Expressão de Função Imediatamente Invocada do formulário(function (name) { return { id: name } })('Jess')
Russ Cam
Muito útil indded! ajuda a identificar problemas no Promises.all esse mapa sobre itens com uma função de seta e você pode perceber se você obtém uma matriz indefinida se nenhum valor foi retornado para o mapeamento sobre a matriz com funções de seta.
Jay shah #
Qual teria sido a desvantagem de tornar sistemático o retorno implícito para as funções de seta? Assim como CoffeeScript faz ... (embora eu não gosto CoffeeScript)
Augustin Riedinger
4
Para ficar claro, parece que, como o analisador JS não sabe se deve esperar uma expressão (como uma expressão que contém um literal de objeto {}) ou um bloco , ele assume que a { }denota um bloco. Isso significa que, quando vê id: name, acha que id:é uma expressão que cria um rótulo (um recurso muito incomum do JS que lida com controle de fluxo e usa a :) e, a nameseguir, id:é simplesmente uma declaração separada que contém apenas a variável name(& faz nada).
iono 31/07
17

Eu entendo essa regra de ouro ...

Para funções que são efetivamente transformadas (manipulação de argumentos de uma linha), o retorno é implícito.

Os candidatos são:

// square-root 
value => Math.sqrt(value)

// sum
(a,b) => a+b

Para outras operações (mais de uma linha que requerem um bloco, o retorno deve ser explícito

Amarsh
fonte
11

Há outro caso aqui.

Ao gravar um componente funcional no React, é possível usar parênteses para agrupar JSX retornado implicitamente.

const FunctionalComponent = () => (
  <div>
    <OtherComponent />
  </div>
);
Deci
fonte
4
Você sempre pode usar parênteses, não está relacionado ao JSX ou ao React.
Emile Bergeron
3

As funções de seta permitem um retorno implícito: os valores são retornados sem a necessidade de usar a returnpalavra - chave.

Funciona quando há uma instrução on-line no corpo da função:

const myFunction = () => 'test'

console.log(myFunction()) //'test'

Outro exemplo, retornando um objeto (lembre-se de colocar os colchetes entre parênteses para evitar que sejam considerados os colchetes da função de empacotamento):

const myFunction = () => ({value: 'test'})

console.log(myFunction()) //{value: 'test'}

Flavio Copes
fonte
1
Essa deve ser a resposta correta, embora precise de um pouco mais de explicação. Basicamente, quando o corpo da função é uma expressão, não um bloco, o valor dessa expressão é retornado implicitamente. Corrija-me se eu estiver errado.
Paul-Sebastian Manole
3

Aqui está outro caso que me deu alguns problemas.

// the "tricky" way
const wrap = (foo) => (bar) => {
  if (foo === 'foo') return foo + ' ' + bar;
  return 'nofoo ' + bar;
}

Aqui, definimos uma função que retorna uma função anônima. O bit "complicado" é que o corpo da função externa (a parte que começa com (bar) => ...) visualmente se parece com um "bloco", mas não é. Como não é, o retorno implícito entra em ação.

Aqui está como o wrap seria executado:

// use wrap() to create a function withfoo()
const withfoo = wrap('foo');
// returns: foo bar
console.log(withfoo('bar'));

// use wrap() to create a function withoutfoo()
const withoutfoo = wrap('bar');
// returns: nofoo bar
console.log(withoutfoo('bar'));

A maneira como eu descompactei isso para garantir que eu entendesse era "desfazer a estreitamento" das funções.

Aqui está o equivalente semântico do primeiro bloco de código, simplesmente fazendo o corpo de wrap () fazer um retorno explícito. Esta definição produz os mesmos resultados que acima. É aqui que os pontos se conectam. Compare o primeiro bloco de código acima com o bloco abaixo e fica claro que uma função de seta é tratada como uma expressão, não como um bloco, e tem o retorno implícito .

// the explicit return way
const wrap = (foo) => {
  return (bar) => {
    if (foo === 'foo') return foo + ' ' + bar;
    return 'nofoo ' + bar;
  }
}

A versão totalmente não-restrita do wrap seria assim, que apesar de não ser tão compacta quanto a versão com flecha, parece muito mais fácil de entender.

// the "no arrow functions" way
const wrap = function(foo) {
  return function(bar) {
    if (foo === 'foo') return foo + ' ' + bar;
    return 'nofoo ' + bar;
  };
};

No final, para outros que talvez precisem ler meu código e me futuro, acho que prefiro usar a versão sem flechas que pode ser compreendida visualmente à primeira vista, em vez da flecha que exige bastante pensei (e no meu caso experimentação) a grok.

grayjohn
fonte