Apa konvensi JavaScript untuk tanpa operasi?

121

Apa konvensi JavaScript untuk tanpa operasi? Seperti passperintah Python .

  • Salah satu opsi hanyalah fungsi kosong: function() {}
  • jQuery menawarkan $.noop(), yang hanya memanggil fungsi kosong di atas.
  • Apakah dapat diterima untuk memasukkan nilai falseatau 0?

Dalam konteks ... semua ini bekerja tanpa menimbulkan kesalahan di 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: Banyak orang menjawab dengan, "jangan lakukan ini! Ubah struktur kode!" Ini mengingatkan saya pada postingan di mana seseorang bertanya bagaimana cara mengendus browser. Dia menerima rentetan postingan yang mengatakan, "JANGAN LAKUKAN! ITU JAHAT," tetapi tidak ada yang memberitahunya cara mengendus browser . Ini bukan review kode. Bayangkan Anda berurusan dengan kode lama yang tidak dapat diubah, dan tanpa beberapa fungsi yang diteruskan, itu akan menimbulkan kesalahan. Atau, sederhananya, itulah yang diinginkan pelanggan, dan mereka membayar saya . Jadi, dengan hormat, harap jawab pertanyaan : Apa cara terbaik untuk menentukan fungsi "tanpa operasi" di JavaScript?

EDIT2: Bagaimana dengan salah satunya?

true;
false;
0;
1;
null;
kmiklas
sumber
7
Mengapa tidak pernyataan if yang sederhana?
epascarello
11
Tak satu pun dari alternatif 0tersebut yang secara efektif lebih baik (atau lebih buruk). Saya akan mengatakan hal yang benar untuk dilakukan adalah if (a === 1) doSomething();dan tidak menggunakan ? :saat itu tidak masuk akal.
Pointy
6
Anda menyalahgunakan operator terner dengan efek samping. Jika Anda harus, lakukanif (statement) action; else ;
mplungjan
Ya falseatau 0akan berhasil; nulladalah cara yang bagus untuk mengekspresikan no-op.
Matt
3
Saya harap terner memiliki beberapa kebutuhan yang tidak dapat kami lihat karena suatu alasan ... Sepertinya Anda mempersulit kode Anda agar terasa keren (Kita semua telah melakukannya!)
Stachu

Jawaban:

95

Untuk menjawab pertanyaan awal, implementasi fungsi noop yang paling elegan dan rapi dalam Javascript murni (seperti yang juga dibahas di sini ) adalah Function.prototype . Hal ini karena:

  1. Function.prototype adalah sebuah fungsi:

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

  1. Itu bisa dipanggil sebagai fungsi dan pada dasarnya tidak melakukan apa-apa seperti yang ditunjukkan di sini:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Meskipun ini adalah "noop sejati" karena sebagian besar browser tampaknya tidak melakukan apa pun untuk menjalankan noop yang didefinisikan dengan cara ini (dan karenanya menghemat siklus CPU), mungkin ada beberapa masalah kinerja yang terkait dengan ini (seperti yang juga disebutkan oleh orang lain di komentar atau di jawaban lain).

Namun, karena itu, Anda dapat dengan mudah menentukan fungsi noop Anda sendiri dan, faktanya, banyak pustaka dan kerangka kerja juga menyediakan fungsi noop. Berikut ini beberapa contohnya:

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

Berikut adalah daftar alfabet dari berbagai implementasi fungsi noop (atau diskusi terkait atau pencarian google):

AngularJS 1.x , Angular 2+ (Tampaknya tidak memiliki implementasi asli - gunakan milik Anda sendiri seperti yang ditunjukkan di atas), Ember , jQuery , Lodash , NodeJS , Ramda , React (Tampaknya tidak memiliki implementasi asli - gunakan milik Anda sendiri seperti yang ditunjukkan di atas), RxJS , Underscore

BAWAH BARIS : Meskipun Function.prototype adalah cara elegan untuk mengekspresikan noop dalam Javascript, namun, mungkin ada beberapa masalah kinerja terkait dengan penggunaannya. Jadi, Anda dapat menentukan dan menggunakan milik Anda sendiri (seperti yang ditunjukkan di atas) atau menggunakan yang ditentukan oleh pustaka / kerangka kerja yang mungkin Anda gunakan dalam kode Anda.

Alan CS
sumber
5
Ini harus menjadi jawabannya. Seseorang bahkan dapat menggunakan Function.prototype()jika Anda tidak memerlukan waktu tunggu dan ingin segera mengeksekusinya.
dimuat
1
setTimeout(Function(), 10000);
iegik
@iegik: +1. Ya kamu benar. Semua berikut ini setara: setTimeout (function () {}, 10000); ATAU setTimeout (Fungsi baru (), 10000); ATAU setTimeout (Function (), 10000); ATAU setTimeout (Function, 10000); karena tata bahasa Javascript dan implementasi konstruktor Fungsi memungkinkan konstruksi ini.
Alan CS
5
Di ES6 atau menggunakan babel atau transpiler lain secara (( )=>{};)teknis Pure JS dan jauh lebih pendek dari function () {}tapi sama persis.
Ray Foss
2
Saya tertarik untuk menemukan konstruksi no-op-like untuk menonaktifkan kode debug secara efisien dalam program saya. Di C / C ++, saya akan menggunakan makro. Saya menguji menetapkan fn saya ke Function.prototype dan mengatur waktunya, membandingkan hasilnya dengan hanya memiliki pernyataan if di dalam fungsi untuk segera kembali. Saya juga membandingkan ini dengan hasil hanya menghapus fungsi sama sekali dari loop. Sayangnya, Function.prototype sama sekali tidak bekerja dengan baik. memanggil fungsi kosong jauh lebih unggul dalam kinerja, bahkan lebih cepat daripada memanggil fungsi dengan tes 'jika' sederhana di dalam untuk mengembalikan.
bearvarine
72

Yang paling ringkas dan noop performant merupakan fungsi panah kosong : ()=>{}.

Fungsi panah bekerja secara native di semua browser kecuali IE (ada transformasi babel jika Anda harus): MDN


()=>{} vs. Function.Prototype

  • ()=>{}adalah 87% lebih cepat dibandingkan Function.prototypedi Chrome 67.
  • ()=>{}adalah 25% lebih cepat daripada Function.prototypedi Firefox 60.
  • ()=>{}adalah 85% lebih cepat dibandingkan Function.prototypedi Ujung (2018/06/15) .
  • ()=>{}adalah kode 65% lebih sedikit dari Function.prototype.

Tes di bawah ini memanas menggunakan fungsi panah untuk memberikan bias Function.prototype, namun fungsi panah adalah pemenangnya:

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.dll
sumber
1
Saya membuat tes jsPerf untuk membandingkan beberapa opsi: noop-function . Tampaknya di Firefox 54, semua alternatif tampaknya hampir setara; di Chromium 58, jauh Function.prototypelebih lambat, tetapi tidak ada opsi lain yang memiliki keuntungan pasti.
Lucas Werkmeister
_=>{}adalah satu karakter kurang dan melakukan hal yang sama.
Ross Attrill
@RossAttrill * hal serupa - _=>{}memiliki satu parameter. Jika seseorang menggunakan TypeScript dengan konfigurasi yang cukup ketat, itu tidak akan dapat dikompilasi. Jika Anda menyebutnya, IDE Anda kemungkinan akan memberi tahu Anda bahwa ia menerima satu parameter yang bisa dari jenis apa pun (baik JavaScript dan terutama TypeScript di vscode).
cchamberlain
15

apa pun yang cenderung Anda capai di sini salah. Ekspresi terner tidak boleh digunakan sebagai pernyataan lengkap, hanya dalam ekspresi, jadi jawaban atas pertanyaan Anda adalah:

tidak ada saran Anda, sebaliknya lakukan:

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

maka kode tersebut mudah dimengerti, dapat dibaca, dan seefisien mungkin.

Mengapa membuatnya lebih sulit, padahal bisa jadi sederhana?

edit:

Jadi, apakah perintah "tanpa operasi" pada dasarnya menunjukkan struktur kode yang lebih rendah?

Anda kehilangan maksud saya. Semua hal di atas adalah tentang ekspresi terner x ? y : z.

Tetapi, perintah tanpa operasi tidak masuk akal dalam bahasa tingkat yang lebih tinggi seperti Javascript.

Ini biasanya digunakan, dalam bahasa tingkat yang lebih rendah seperti assembly atau C, sebagai cara untuk membuat prosesor tidak melakukan apa pun untuk satu instruksi untuk tujuan pengaturan waktu.

Di JS, apakah Anda melakukan 0;, null;, function () {};atau pernyataan kosong, ada kemungkinan besar bahwa itu akan diabaikan oleh interpretor ketika membaca, tapi sebelum itu akan ditafsirkan, sehingga pada akhirnya, Anda hanya akan membuat program anda menjadi dimuat lebih lambat dengan waktu yang sangat singkat. Nota Bene : Saya berasumsi demikian, karena saya tidak terlibat dalam interpreter JS yang banyak digunakan, dan ada kemungkinan setiap interpreter memiliki strateginya sendiri.

Jika Anda menggunakan sesuatu yang sedikit lebih rumit, seperti $.noop()atau var foo = function () {}; foo(), maka interpreter dapat melakukan panggilan fungsi yang tidak berguna yang pada akhirnya akan merusak beberapa byte tumpukan fungsi Anda, dan beberapa siklus.

Satu-satunya alasan saya melihat fungsi seperti $.noop()akan ada, adalah masih bisa memberikan fungsi callback ke beberapa fungsi event yang akan memunculkan pengecualian jika tidak bisa memanggil callback itu. Tapi kemudian, itu perlu fungsi yang perlu Anda berikan, dan memberinya noopnama adalah ide yang bagus sehingga Anda memberi tahu pembaca Anda (dan itu mungkin Anda dalam 6 bulan) bahwa Anda sengaja memberikan fungsi kosong.

Pada akhirnya, tidak ada yang namanya struktur kode "inferior" atau "superior". Anda benar atau salah dalam cara Anda menggunakan perkakas .. Menggunakan terner sebagai contoh Anda seperti menggunakan palu saat Anda ingin memasang sekrup. Ini akan berhasil, tetapi Anda tidak yakin Anda dapat menggantung sesuatu di sekrup itu.

Apa yang dapat dianggap sebagai "inferior" atau "superior" adalah algoritme dan ide yang Anda masukkan ke dalam kode. Tapi itu hal lain.

zmo
sumber
1
Jadi, apakah perintah "tanpa operasi" pada dasarnya menunjukkan struktur kode yang lebih rendah?
kmiklas
3
@kmiklas: Saya tidak bisa mengatakan saya pernah menemukan kebutuhan sah untuk NOOP, di luar assembler.
Matt Burland
@zmo: Saya mengerti maksud Anda tentang bagaimana komentar Anda berhubungan dengan ekspresi terner; semua orang tampaknya telah melewatkan maksud saya bahwa ini hanyalah contoh ilustrasi dari panggilan ke fungsi "No Operation".
kmiklas
1
Tentu ada alasan untuk menginginkan / membutuhkan fitur no-op. Jangan membuat generalisasi luas berdasarkan pemikiran mendalam Anda selama 12 detik tentang sesuatu. JavaScript adalah bahasa yang membuat fungsi dapat dikontrol sepenuhnya sebagai variabel. Misalkan Anda memiliki kebutuhan untuk menonaktifkan fungsi tanpa pengujian eksplisit? Ini akan sempurna untuk itu. Jika Anda memiliki fungsi yang sering muncul, seperti pernyataan debug, alangkah baiknya jika Anda dapat menonaktifkannya dengan menetapkan ulang fungsi ke no-op daripada harus menambahkan kode tambahan untuk menguji beberapa variabel setiap kali fungsi tersebut muncul .
bearvarine
2
@bearvarine terima kasih atas opini tinggi yang Anda miliki tentang saya :-D. Anda benar dalam komentar Anda, tetapi ini bukan untuk desain kode, hanya desain mockup menggunakan retasan. Apa yang Anda gambarkan juga disebut menambal monyet, dan ada alasan untuk itu ;-)
zmo
7

Saya pikir jQuery noop()sebagian besar dimaksudkan untuk mencegah kode mogok dengan menyediakan fungsi default ketika yang diminta tidak tersedia. Misalnya, dengan mempertimbangkan contoh kode berikut, $.noopdipilih jika fakeFunctiontidak ditentukan, mencegah panggilan berikutnya ke tidak bekerja fn:

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

Kemudian, noop()izinkan untuk menghemat memori dengan menghindari menulis fungsi kosong yang sama beberapa kali di mana pun dalam kode Anda. Ngomong-ngomong, $.noopini sedikit lebih pendek dari function(){}(6 byte disimpan per token). Jadi, tidak ada hubungan antara kode Anda dan pola fungsi kosong. Gunakan null, falseatau 0jika Anda suka, dalam kasus Anda tidak akan ada efek samping. Selain itu, perlu dicatat bahwa kode ini ...

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

... sama sekali tidak berguna karena Anda tidak akan pernah memanggil fungsinya, dan yang ini ...

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

... bahkan lebih tidak berguna karena Anda memanggil fungsi kosong, yang persis sama dengan ...

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

Mari kita ganti ekspresi terner dengan ifpernyataan untuk melihat seberapa tidak berguna:

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

Anda cukup menulis:

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

Atau bahkan lebih pendek:

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

Untuk akhirnya menjawab pertanyaan Anda, saya kira "tidak ada operasi konvensional" adalah yang tidak pernah ditulis.

daun
sumber
1
Namun terkadang Anda harus menyediakan fungsi. Misalnya dengan promise maka (fn, fn) terkadang Anda ingin memberikan fungsi kedua tetapi bukan fungsi pertama. oleh karena itu Anda membutuhkan sesuatu untuk tempat dudukan ...mypromise.then($.noop, myErrorhandler);
John Henckel
3

Saya menggunakan:

 (0); // nop

Untuk menguji waktu eksekusi, jalankan sebagai:

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

hasil: tandai: 0.000ms

Menggunakan Boolean( 10 > 9)dapat direduksi menjadi ( 10 > 9)yang kembali true. Datang dengan ide untuk menggunakan satu operan, saya sepenuhnya berharap (0);akan kembalifalse , tetapi itu hanya mengembalikan argumen kembali seperti yang dapat ditinjau dengan melakukan tes ini di konsol.

> var a = (0);
< undefined
> a
< 0
Telur
sumber
1
banyak yang mencoba ini akan mendapatkanargument 0 is not a function
Code Whisperer
4
Anda hanya menetapkan 0. IMO noopharus menjadi fungsi yang mengevaluasi undefinedhasil.
cchamberlain
1
Bagaimana pernyataan ini (0); menetapkan 0 ?, di mana var dan tanda sama dengan? Tidak ada nama fungsi di depan (0), jadi saya tidak melihat bagaimana ini bisa menjadi argumen? jika Anda mencoba typeof ((0)), itu kembali sebagai angka. Ketika saya menjawab pertanyaan tersebut, saya memberikan pernyataan yang saya gunakan untuk meniru NOP, tetapi saya bersedia mengubah jawaban saya untuk hanya menggunakan; untuk mewakili pernyataan kosong
Telur
1
Saya pikir (0); adalah solusi yang dapat diterima untuk pertanyaan OP. Saya pikir orang-orang menjadi bingung karena mereka menemukan halaman ini sambil mencari fungsi yang tidak melakukan apa-apa, daripada pernyataan yang tidak melakukan apa-apa. OP tidak membantu dengan menyarankan awalnya function(){}sebagai solusi. Menelepon (0)()akan menyebabkanTypeError: 0 is not a function
Benjamin
Saya mengacu pada var a = (0);. Tidak ada operasi seharusnya tidak mengubah memori dan contoh tugas Anda melakukan hal itu. Itu (0)sendiri dapat dianggap sebagai no-op yang tidak berguna (ada jumlah yang tak terbatas di JavaScript sehingga tidak ada yang membuat contoh Anda di sini istimewa).
cchamberlain
2

Sama sekali tidak ada masalah atau penalti performa jika menggunakan Function.prototypeover() => {} .

Manfaat utama dari Function.prototypeadalah memiliki fungsi tunggal daripada mendefinisikan ulang fungsi anonim baru setiap saat. Sangat penting untuk menggunakan no-op likeFunction.prototype saat menentukan nilai default dan memo karena memberi Anda penunjuk objek yang konsisten yang tidak pernah berubah.

Alasan saya merekomendasikan Function.prototypedaripada Functionkarena mereka tidak sama:

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

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

Selain itu, tolok ukur dari jawaban lain menyesatkan . Nyatanya, Function.prototypebekerja lebih cepat daripada () => {}bergantung pada cara Anda menulis dan menjalankan tolok ukur:

Anda tidak bisa mempercayai tolok ukur JS << Secara khusus menyebutkan tolok ukur pada pertanyaan ini.

Jangan mengatur kode Anda dari tolok ukur; lakukan apa pun yang bisa dipelihara dan biarkan penerjemah mencari cara untuk mengoptimalkan dalam jangka panjang.

Sawtaytoes
sumber