Qual é a convenção de JavaScript para nenhuma operação?

121

Qual é a convenção de JavaScript para nenhuma operação? Como um passcomando Python .

  • Uma opção é simplesmente uma função vazia: function() {}
  • jQuery oferece $.noop(), que simplesmente chama a função vazia acima.
  • É aceitável simplesmente inserir um valor de falseou 0?

No contexto ... tudo isso funciona sem gerar um erro no Chrome:

var a = 2;
(a === 1) ? alert(1) : function() {};
(a === 1) ? alert(1) : $.noop();
(a === 1) ? alert(1) : false;
(a === 1) ? alert(1) : 0;

EDIT: Muitas pessoas responderam com: "não faça isso! Mude a estrutura do código!" Isso me lembra de uma postagem em que alguém perguntou como farejar o navegador. Ele recebeu uma enxurrada de postagens dizendo: "NÃO FAÇA ISSO! É MAL", mas ninguém lhe disse como farejar o navegador . Esta não é uma revisão de código. Imagine que você esteja lidando com um código legado que não pode ser alterado e, sem alguma função transmitida, ele apresentará um erro. Ou, simplesmente, é assim que o cliente deseja e está me pagando . Portanto, respeitosamente, responda à pergunta : Qual é a melhor maneira de especificar uma função "sem operação" em JavaScript?

EDIT2: Que tal um desses?

true;
false;
0;
1;
null;
kmiklas
fonte
7
Por que não uma simples declaração if?
epascarello de
11
Nenhuma dessas alternativas 0é efetivamente melhor (ou pior). Eu diria que a coisa certa a fazer é if (a === 1) doSomething();e não usar ? :quando não fizer sentido.
Pointy de
6
Você está abusando do operador ternário com um efeito colateral. Se necessário, façaif (statement) action; else ;
mplungjan
Sim falseou 0funcionará; nullé uma boa maneira de expressar no-op.
Matt
3
Espero que o ternário tenha alguma necessidade que não possamos ver por algum motivo ... Parece que você está complicando seu código para ficar legal (todos nós fizemos isso!)
Stachu

Respostas:

95

Para responder à pergunta original, a implementação mais elegante e organizada de uma função noop em Javascript puro (como também é discutido aqui ) é Function.prototype . Isto é porque:

  1. Function.prototype é uma função:

typeof Function.prototype === "function" // returns true

  1. Ele pode ser chamado como uma função e essencialmente não faz nada conforme mostrado aqui:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Embora este seja um "noop verdadeiro", uma vez que a maioria dos navegadores parece não fazer nada para executar o noop definido desta forma (e, portanto, salvar os ciclos da CPU), pode haver alguns problemas de desempenho associados a isso (como também é mencionado por outros em comentários ou em outras respostas).

No entanto, dito isso, você pode definir facilmente sua própria função noop e, de fato, muitas bibliotecas e estruturas também fornecem funções noop. Abaixo estão alguns exemplos:

var noop = function () {};           // Define your own noop in ES3 or ES5
const noop = () => {};               // Define in ES6 as Lambda (arrow function)
setTimeout(noop, 10000);             // Using the predefined noop

setTimeout(function () {} , 10000);  // Using directly in ES3 or ES5
setTimeout(() => {} , 10000);        // Using directly in ES6 as Lambda (arrow function)

setTimeout(angular.noop, 10000);     // Using with AngularJS 1.x
setTimeout(jQuery.noop, 10000);      // Using with jQuery

Aqui está uma lista em ordem alfabética de várias implementações de funções noop (ou discussões relacionadas ou pesquisas no Google):

AngularJS 1.x , Angular 2+ (não parece ter uma implementação nativa - use a sua própria como mostrado acima), Ember , jQuery , Lodash , NodeJS , Ramda , React (não parece ter uma implementação nativa - use a sua como mostrado acima), RxJS , sublinhado

CONCLUSÃO : Embora Function.prototype seja uma maneira elegante de expressar um noop em Javascript, no entanto, pode haver alguns problemas de desempenho relacionados ao seu uso. Portanto, você pode definir e usar o seu próprio (como mostrado acima) ou usar um definido pela biblioteca / estrutura que você pode estar usando em seu código.

Alan CS
fonte
5
Esta deve ser a resposta. Pode- Function.prototype()se usar até mesmo se você não precisar do tempo limite e quiser que ele seja executado imediatamente.
Springloaded
1
setTimeout(Function(), 10000);
iegik
@iegik: +1. Sim você está correto. Todos os seguintes são equivalentes: setTimeout (function () {}, 10000); OU setTimeout (new Function (), 10000); OR setTimeout (Function (), 10000); OU setTimeout (Função, 10000); já que a gramática Javascript e a implementação do construtor Function permitem essas construções.
Alan CS de
5
Em ES6 ou usando babel ou outro transpiler (( )=>{};)tecnicamente Pure JS e muito mais curto do que, function () {}mas exatamente equivalente.
Ray Foss
2
Eu estava interessado em encontrar uma construção do tipo no-op para desligar com eficiência o código de depuração em meu programa. Em C / C ++, eu teria usado macros. Testei atribuir meu fn a Function.prototype e o cronometrei, comparando os resultados a simplesmente ter uma instrução if dentro da função para retornar imediatamente. Eu também comparei isso com os resultados de simplesmente remover a função completamente do loop. Infelizmente, Function.prototype não teve um bom desempenho. chamar uma função vazia era muito superior em desempenho, ainda mais rápido do que chamar a função com o simples teste 'if' interno para retornar.
bearvarine
72

O mais concisa e noop performance é uma função seta vazia : ()=>{}.

As funções de seta funcionam nativamente em todos os navegadores, exceto no IE (há uma transformação babel, se necessário): MDN


()=>{} vs. Function.Prototype

  • ()=>{}é 87% mais rápido do que Function.prototypeno Chrome 67.
  • ()=>{}é 25% mais rápido do que Function.prototypeno Firefox 60.
  • ()=>{}é 85% mais rápido do que Function.prototypeno Edge (15/06/2018) .
  • ()=>{}é 65% menos código do que Function.prototype.

O teste abaixo esquenta usando a função de seta para dar um viés Function.prototype, mas a função de seta é a vencedora:

const noop = ()=>{};
const noopProto = Function.prototype;

function test (_noop, iterations) {
    const before = performance.now();
    for(let i = 0; i < iterations; i++) _noop();
    const after = performance.now();
    const elapsed = after - before;
    console.info(`${elapsed.toFixed(4)}MS\t${_noop.toString().replace('\n', '')}\tISNOOP? ${_noop() === undefined}`);
    return elapsed;
}

const iterations = 10000000
console.info(`noop time for ${iterations.toLocaleString()} iterations`)
const timings = {
    noop: test(noop, iterations),
    noopProto: test(noopProto, iterations)
}

const percentFaster = ((timings.noopProto - timings.noop)/timings.noopProto).toLocaleString("en-us", { style: "percent" });
console.info(`()=>{} is ${percentFaster} faster than Function.prototype in the current browser!`)

cchamberlain
fonte
1
Criei um teste jsPerf para comparar algumas opções: função noop . Parece que no Firefox 54, todas as alternativas parecem ser quase equivalentes; no Chromium 58, Function.prototypeé drasticamente mais lento, mas nenhuma das outras opções tem uma vantagem definitiva.
Lucas Werkmeister
_=>{}é um personagem a menos e faz a mesma coisa.
Ross Attrill
@RossAttrill * coisa semelhante - _=>{}tem um único parâmetro. Se alguém estiver usando o TypeScript com uma configuração razoavelmente estrita, isso não será compilado. Se você chamá-lo, seu IDE provavelmente dirá que aceita um único parâmetro que pode ser de qualquer tipo (JavaScript e, especialmente, TypeScript em vscode).
cchamberlain
15

tudo o que você tende a conseguir aqui está errado. As expressões ternárias não devem ser usadas como uma declaração completa, apenas na expressão, portanto, a resposta à sua pergunta é:

nenhuma de suas sugestões, em vez disso:

var a = 2;
if (a === 1)
    alert(1)
// else do nothing!

então o código é facilmente compreensível, legível e tão eficiente quanto possível.

Por que tornar mais difícil, quando pode ser simples?

editar:

Então, um comando de "não operação" indica basicamente uma estrutura de código inferior?

Você está perdendo o meu ponto. Tudo o que foi dito acima é sobre a expressão ternária x ? y : z.

Porém, um comando no operation não faz sentido em linguagens de nível superior, como Javascript.

Geralmente é usado, em linguagens de nível inferior, como assembly ou C, como uma maneira de fazer o processador não fazer nada por uma instrução para fins de temporização.

Em JS, se você faz 0;, null;, function () {};ou uma declaração vazia, há grandes chances de que ele será ignorado pelo intérprete quando ele é lê-lo, mas antes que ele obtém interpretado, assim, no final, você só vai fazer o seu programa ser carregado mais lentamente por um período de tempo muito pequeno. Nota Bene : Estou supondo isso, pois não estou envolvido em nenhum interpretador JS amplamente usado e há chances de cada interpretador ter sua própria estratégia.

No caso de você usar algo um pouco mais complicado, como $.noop()ou var foo = function () {}; foo(), então o interpretador pode fazer uma chamada de função inútil que acabará estragando alguns bytes de sua pilha de funções e alguns ciclos.

A única razão pela qual vejo uma função como $.noop()existiria seria para ainda ser capaz de fornecer uma função de retorno de chamada para alguma função de evento que lançaria uma exceção se não pudesse chamar esse retorno de chamada. Mas então, é necessariamente uma função que você precisa fornecer, e dar a ela o noopnome é uma boa ideia, então você está dizendo aos seus leitores (e isso pode ser você em 6 meses) que você atribuiu uma função vazia de propósito.

No final das contas, não existe estrutura de código "inferior" ou "superior". Você está certo ou errado na maneira como usa suas ferramentas. Usar um ternário como exemplo é como usar um martelo para aparafusar. Vai funcionar, mas você não tem certeza de que pode pendurar algo nesse parafuso.

O que pode ser considerado "inferior" ou "superior" é o algoritmo e as ideias que você colocou em seu código. Mas isso é outra coisa.

zmo
fonte
1
Então, um comando de "não operação" indica basicamente uma estrutura de código inferior?
kmiklas
3
@kmiklas: Não posso dizer que já encontrei uma necessidade legítima de um NOOP, fora do assembler.
Matt Burland
@zmo: Eu entendo seu ponto de vista sobre como seus comentários se relacionam com a expressão ternária; todos parecem ter perdido meu ponto de vista de que este era apenas um exemplo ilustrativo de uma chamada para a função "Sem operação".
kmiklas de
1
Claro que há razões para querer / precisar de um recurso autônomo. Não faça generalizações amplas com base em seus 12 segundos de reflexão profunda sobre algo. JavaScript é uma linguagem que torna as funções totalmente controláveis ​​como variáveis. Suponha que você precise desabilitar uma função sem um teste explícito. Isso seria perfeito para isso. Se você tem uma função que aparece com frequência, como uma instrução de depuração, seria bom poder desligá-la reatribuindo a função para ambiente autônomo em vez de ter que adicionar código extra para testar alguma variável cada vez que a função aparecer .
bearvarine
2
@bearvarine, obrigado pela opinião que você tem de mim :-D. Você está absolutamente certo em seu comentário, mas não é realmente para design de código, apenas design de maquete usando um hack. O que você descreve também é chamado de monkey patching, e há uma razão para isso ;-)
zmo
7

Acho que o noop()objetivo principal do jQuery é impedir o código de travar, fornecendo uma função padrão quando a solicitada não está disponível. Por exemplo, considerando o seguinte exemplo de código, $.noopé escolhido se fakeFunctionnão estiver definido, evitando que a próxima chamada para fntravar:

var fn = fakeFunction || $.noop;
fn() // no crash

Em seguida, noop()permite economizar memória evitando escrever a mesma função vazia várias vezes em todo o código. A propósito, $.noopé um pouco menor que function(){}(6 bytes salvos por token). Portanto, não há relacionamento entre o seu código e o padrão de função vazio. Use null, falseou 0se quiser, no seu caso não haverá efeito colateral. Além disso, é importante notar que este código ...

true/false ? alert('boo') : function(){};

... é completamente inútil já que você nunca chamará a função, e esta ...

true/false ? alert('boo') : $.noop();

... é ainda mais inútil, pois você chama uma função vazia, que é exatamente o mesmo que ...

true/false ? alert('boo') : undefined;

Vamos substituir a expressão ternária por uma ifdeclaração para ver o quanto é inútil:

if (true/false) {
    alert('boo');
} else {
    $.noop(); // returns undefined which goes nowhere
}

Você pode simplesmente escrever:

if (true/false) alert('boo');

Ou ainda mais curto:

true/false && alert('boo');

Para finalmente responder à sua pergunta, acho que "nenhuma operação convencional" é aquela que nunca é escrita.

folha
fonte
1
No entanto, às vezes você precisa fornecer uma função. Por exemplo, com promises then (fn, fn), às vezes você deseja fornecer a segunda função, mas não a primeira função. portanto, você precisa de algo para um marcador de posição ...mypromise.then($.noop, myErrorhandler);
John Henckel
3

Eu uso:

 (0); // nop

Para testar o tempo de execução desta execução como:

console.time("mark");
(0); // nop
console.timeEnd("mark");

resultado: marca: 0,000ms

O uso Boolean( 10 > 9)pode ser reduzido a simplesmente o ( 10 > 9)que retorna true. Tendo a ideia de usar um único operando que eu esperava totalmente, (0);ele retornaria false, mas ele simplesmente retorna o argumento, conforme pode ser revisado executando este teste no console.

> var a = (0);
< undefined
> a
< 0
Ovos
fonte
1
muitos que tentarem isso obterãoargument 0 is not a function
Codigo Whisperer
4
Você está simplesmente atribuindo 0. IMO noopdeve ser uma função que avalia com undefinedresultado.
cchamberlain
1
Como é essa afirmação (0); atribuindo um 0 ?, onde está var e o sinal de igual? Não há nome de função antes de (0), então não vejo como isso pode ser um argumento. se você tentar typeof ((0)), ele volta como um número. Quando respondi à pergunta, estava fornecendo uma declaração que uso para imitar um NOP, mas estou disposto a mudar minha resposta para simplesmente usar; para representar uma declaração vazia
Ovos
1
Eu acho (0); é uma solução aceitável para a pergunta de OP. Acho que as pessoas estão ficando confusas porque encontraram esta página enquanto procuravam uma função que não faz nada, em vez de uma instrução que não faz nada. O OP não está ajudando, sugerindo inicialmente function(){}como uma solução. Chamar (0)()causaráTypeError: 0 is not a function
Benjamin
Eu estava me referindo var a = (0);. Um ambiente autônomo não deve mudar a memória e seu exemplo de atribuição faz exatamente isso. O (0)por si só pode ser considerado um ambiente autônomo inútil (há um número infinito deles em JavaScript, então não há nada que torne seu exemplo especial aqui).
cchamberlain
2

Não há absolutamente nenhum problema ou desempenho penalidade de usar Function.prototypemais () => {}.

O principal benefício Function.prototypeé ter uma função singleton em vez de redefinir uma nova função anônima a cada vez. É especialmente importante usar um Function.prototypeambiente autônomo ao definir valores padrão e memoizing, pois ele fornece um ponteiro de objeto consistente que nunca muda.

O motivo pelo qual estou recomendando, Function.prototypee não Functionporque eles não são iguais:

Function() === Function()
// false

Function.prototype() === Function.prototype()
// true

Além disso, os benchmarks de outras respostas são enganosos . Na verdade, tem um Function.prototypedesempenho mais rápido do que () => {}dependendo de como você escreve e executa o benchmark:

Você não pode confiar nos benchmarks JS << Referindo especificamente os benchmarks nesta questão.

Não estilize seu código a partir de benchmarks; faça tudo o que for passível de manutenção e deixe o interpretador descobrir como otimizar a longo prazo.

Sawtaytoes
fonte