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());
}


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.


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.


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.


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);


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)


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,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.