Usando a variável _ (sublinhado) com funções de seta em ES6 / Typescript

119

Eu me deparei com essa construção em um exemplo Angular e me pergunto por que isso foi escolhido:

_ => console.log('Not using any parameters');

Eu entendo que a variável _ significa não me importo / não usado, mas como é a única variável, há alguma razão para preferir o uso de _ em vez de:

() => console.log('Not using any parameters');

Certamente isso não pode ser cerca de um caractere a menos para digitar. A sintaxe () transmite melhor a intenção na minha opinião e também é mais específica do tipo, porque caso contrário, acho que o primeiro exemplo deveria ser assim:

(_: any) => console.log('Not using any parameters');

Caso seja importante, este foi o contexto onde foi usado:

submit(query: string): void {
    this.router.navigate(['search'], { queryParams: { query: query } })
      .then(_ => this.search());
}
Halt
fonte
1
Como você pode se preocupar com a digitação ou especificidade de tipo para um parâmetro que nunca é usado?
3
Sou um desenvolvedor C ++ profissional, então acho que estou sempre preocupado com a especificidade de tipo :-).
Parada em
6
Pessoalmente, o padrão _ => reduz o número de colchetes, facilitando a leitura: doStuff (). Then (() => action ()) vs doStuff (). Then (_ => action ()).
Damien Golding

Respostas:

93

A razão pela qual este estilo pode ser usado (e possivelmente porque foi usado aqui) é que _é um caractere mais curto que ().

Os parênteses opcionais têm o mesmo tipo de problema de estilo que as chaves opcionais . Esta é uma questão de gosto e estilo de código na maior parte, mas a verbosidade é favorecida aqui por causa da consistência.

Embora as funções de seta permitam um único parâmetro sem parênteses, é inconsistente com zero, desestruturação única, descanso único e vários parâmetros:

let zeroParamFn = () => { ... };
let oneParamFn = param1 => { ... };
let oneParamDestructuredArrFn = ([param1]) => { ... };
let oneParamDestructuredObjFn = ({ param1 }) => { ... };
let twoParamsFn = (param1, param2) => { ... };
let restParamsFn = (...params) => { ... };

Embora o is declared but never usederro tenha sido corrigido no TypeScript 2.0 para parâmetros sublinhados, _também pode disparar um unused variable/parameteraviso de um linter ou IDE. Este é um argumento considerável contra isso.

_pode ser usado convencionalmente para parâmetros ignorados (como a outra resposta já explicada). Embora isso possa ser considerado aceitável, esse hábito pode resultar em um conflito com o _namespace Underscore / Lodash, também parece confuso quando há vários parâmetros ignorados. Por esse motivo, é benéfico ter parâmetros sublinhados corretamente nomeados (com suporte no TS 2.0), também economiza tempo ao descobrir a assinatura da função e por que os parâmetros são marcados como ignorados (isso desafia o propósito do _parâmetro como um atalho):

let fn = (param1, _unusedParam2, param3) => { ... };

Pelas razões listadas acima, eu pessoalmente consideraria o _ => { ... }estilo de código um tom ruim que deve ser evitado.

Estus Flask
fonte
1
É um caractere a menos, mas é a mesma quantidade de teclas pressionadas para a maioria dos IDEs, já que pressionar o (geralmente vem com um ). Pessoalmente, prefiro usar o pparâmetro para, também me pergunto se há algum problema de desempenho
Mojimi
68

A ()sintaxe transmite a intenção melhor imho e também é mais específica do tipo

Não exatamente. ()diz que a função não espera nenhum argumento, ela não declara nenhum parâmetro. A função .lengthé 0.

Se você usar _, ele afirma explicitamente que a função receberá um argumento, mas que você não se importa com isso. A função .lengthserá 1, o que pode ser importante em algumas estruturas.

Então, de uma perspectiva de tipo, pode ser a coisa mais precisa a fazer (especialmente quando você não digita com anymas, digamos, _: Event). E como você disse, é um caractere a menos para digitar, o que também é mais fácil de alcançar em alguns teclados.

Bergi
fonte
6
Meu primeiro pensamento foi que _ torna óbvio apenas por convenção que não há argumentos a serem considerados ao tentar entender a função. O uso de () torna isso explícito, sem necessidade de escanear o código para um possível uso de _ (o que violaria a convenção). Mas você abriu meus olhos para considerar também o valor de documentar que há um valor passado para a função que, de outra forma, nem sempre seria óbvio.
Parada em
Acabei de perceber que meu código está cheio de _variáveis ​​de função de seta s não utilizadas , me pergunto se há alguma diferença de desempenho em comparação com o uso()
Mojimi
24

Acho que _ =>é usado () =>porque _é comum em outras linguagens onde não é permitido apenas omitir parâmetros como em JS.

_ é popular no Go e também é usado no Dart para indicar que um parâmetro é ignorado e provavelmente outros que não conheço.

Günter Zöchbauer
fonte
4
Python também segue essa convenção, eu acho.
Jaime RGP
7
Esse uso de _foi presumivelmente emprestado de linguagens funcionais como ML e Haskell, onde é muito anterior à invenção do Python (sem falar em Go, Dart ou TypeScript).
ruakh
1
também Ruby faz isso ( po-ru.com/diary/rubys-magic-underscore ) e F # também (e outras linguagens influenciadas pela família ML)
Mariusz Pawelski
Scala adora sublinhado ( includehelp.com/scala/use-of-underscore-in-scala.aspx ). Quais outras linguagens seguiram o que Scala está fazendo com tipos anônimos com sublinhado.
Sam
Eu acho que Scala também tirou isso de alguma outra linguagem. Quase não há nada em linguagens de programação que não existisse nos anos 70: D Principalmente, apenas novas maneiras de combinar as coisas.
Günter Zöchbauer
11

É possível distinguir entre os dois usos, e alguns frameworks usam isso para representar diferentes tipos de callbacks. Por exemplo, acho que o framework nodes express usa isso para distinguir entre tipos de middleware, por exemplo, manipuladores de erros usam três argumentos, enquanto o roteamento usa dois.

Essa diferenciação pode ser semelhante ao exemplo abaixo:

const f1 = () => { } // A function taking no arguments
const f2 = _ => { }  // A function with one argument that doesn't use it

function h(ff) { 
  if (ff.length === 0) {
    console.log("No argument function - calling directly");
    ff();
  } else if (ff.length === 1) {
    console.log("Single argument function - calling with 1");
    ff(1);
  }
}

h(f1);
h(f2);

Michael Anderson
fonte
1
Isso é baseado na resposta de Bergi, mas achei que adicionar um exemplo fosse um pouco mais de edição do que eu gostaria de fazer na postagem de outra pessoa.
Michael Anderson
0

Quando escrevi o post fiquei com a impressão de que _era a única maneira de criar funções de flecha sem (), o que me levou a acreditar que usar _poderia ter algumas pequenas vantagens, mas me enganei. @Halt confirmou nos comentários que se comporta como outras variáveis, não é uma construção de linguagem especial.


Quero mencionar mais uma coisa que percebi sobre essas funções de seta de sublinhado enquanto me testava e não encontrei mencionado em lugar nenhum. Você pode usar o sublinhado na função como um parâmetro , embora esse provavelmente não seja o uso pretendido, já que ele deve representar um parâmetro não usado. Para maior clareza, eu realmente não recomendo usá-lo dessa forma. mas pode ser útil saber coisas como codegolf , desafios em que você escreve o código mais curto (parece que você pode usar qualquer caractere sem isso ()). Eu poderia imaginar alguns casos de uso reais em que as bibliotecas usam isso e você precisa usá-lo, mesmo que elas não pretendessem ter essa funcionalidade.

Exemplo:

// simple number doubling function
f = _=> {
    _ = _ * 2;
    return _;
}

console.log(f(2)); // returns 4
console.log(f(10)); // returns 20

Testado com o console do Chrome, versão 76.0.3809.132 (versão oficial) (64 bits)

Matsyir
fonte
1
O sublinhado '_' é um nome de variável válido e não uma construção de linguagem especial, apenas com um significado especial por convenção. Os avisos de Linter sobre parâmetros não utilizados podem ser silenciados usando o prefixo de sublinhado. Eu acho que _ por si só é apenas a maneira mais curta de dizer não utilizado.
Parada em
@Halt Obrigado pelo esclarecimento, é bom saber com certeza. Na verdade, eu não sabia que você poderia fazer funções de seta sem o ()antes de fazer este post, pensei que _era a única maneira, por isso decidi apontar isso. Com isso em mente, não é nada especial para usar, mesmo para jogar golfe, já que você poderia usar apenas um caractere normal. Melhor usado simplesmente para seguir convenções, como você disse.
Matsyir,