İşlemsiz JavaScript kuralı nedir?


121

İşlemsiz JavaScript kuralı nedir? Bir Python passkomutu gibi.

  • Seçeneklerden biri boş bir işlevdir: function() {}
  • jQuery, $.noop()yukarıdaki boş işlevi çağıran teklifler .
  • Basitçe falseveya değerinin girilmesi kabul edilebilir 0mi?

Bağlamda ... bunların tümü Chrome'da hata vermeden çalışır:

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

DÜZENLEME: Birçok kişi "bunu yapma! Kod yapısını değiştirin!" Bu bana, birinin tarayıcının nasıl koklanacağını sorduğu bir gönderiyi hatırlattı. "BUNU YAPMAYIN! BU KÖTÜ" diyen bir dizi gönderi aldı, ancak kimse ona tarayıcının nasıl koklanacağını söylemedi . Bu bir kod incelemesi değildir. Değiştirilemeyen eski bir kodla uğraştığınızı ve bazı işlevler devredilmezse, bunun bir hata vereceğini hayal edin. Ya da basitçe, müşteri bunu istiyor ve bana ödeme yapıyorlar . Bu nedenle, saygılı bir şekilde, lütfen şu soruyu yanıtlayın : JavaScript'te "işlem yok" işlevini belirtmenin en iyi yolu nedir?

EDIT2: Bunlardan birine ne dersiniz?

true;
false;
0;
1;
null;

7
Neden basit bir if ifadesi değil?
epascarello

11
Bu alternatiflerin hiçbiri 0etkili bir şekilde daha iyi (veya daha kötü) değildir. Yapılması gereken doğru şeyin, mantıklı if (a === 1) doSomething();olmadığında kullanmamaktır ? :.
Pointy

6
Üçlü operatörü bir yan etki ile kötüye kullanıyorsunuz. Yapmanız gerekiyorsa, yapınif (statement) action; else ;
mplungjan

Evet falseveya 0işe yarayacak; nullişlem yapılmadığını ifade etmenin güzel bir yoludur.
Matt

3
Umarım üçlü bir nedenden ötürü göremediğimiz bir gereklilik vardır ... Kodunuzu havalı hissetmek için karmaşık hale getiriyorsunuz (Hepimiz
başardık

Yanıtlar:


95

Orijinal soruyu yanıtlamak için, saf Javascript'te bir noop işlevinin en zarif ve düzgün uygulaması ( burada da tartışıldığı gibi ) Function.prototype'dir . Bunun nedeni ise:

  1. Function.prototype bir işlevdir:

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

  1. Bir işlev olarak çağrılabilir ve esasen burada gösterildiği gibi hiçbir şey yapmaz:
setTimeout(function() {
      console.log('Start: ', Date.now());
      Function.prototype();
      console.log('End  : ', Date.now());
    }, 1000);

Bu bir "gerçek noop" olmasına rağmen, çoğu tarayıcı bu şekilde tanımlanan noop'u yürütmek için hiçbir şey yapmıyor gibi görünse de (ve dolayısıyla CPU döngülerini kurtarıyor), bununla ilişkili bazı performans sorunları olabilir (başkalarının da yorumlarda veya diğer cevaplar).

Bununla birlikte, kendi noop işlevinizi kolayca tanımlayabilirsiniz ve aslında birçok kitaplık ve çerçeve de noop işlevleri sağlar. Aşağıda bazı örnekler verilmiştir:

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

Noop işlevlerinin (veya ilgili tartışmaların veya google aramalarının) çeşitli uygulamalarının alfabetik bir listesi:

AngularJS 1.x , Angular 2+ (Yerel bir uygulamaya sahip gibi görünmüyor - yukarıda gösterildiği gibi kendi uygulamanızı kullanın), Ember , jQuery , Lodash , NodeJS , Ramda , React (Yerel bir uygulamaya sahip görünmüyor - kendi uygulamanızı kullanın yukarıda gösterildiği gibi), RxJS , Alt Çizgi

Özet : Function.prototype, Javascript'te noop'u ifade etmenin zarif bir yolu olsa da, kullanımıyla ilgili bazı performans sorunları olabilir. Böylece, kendi kodunuzu (yukarıda gösterildiği gibi) tanımlayabilir ve kullanabilir veya kodunuzda kullanıyor olabileceğiniz kitaplık / çerçeve tarafından tanımlanan birini kullanabilirsiniz.


5
Cevap bu olmalı. Function.prototype()Zaman aşımına ihtiyacınız yoksa ve hemen yürütülmesini istiyorsanız bile kullanabilirsiniz .
2015'te

1
setTimeout(Function(), 10000);
iegik

@iegik: +1. Evet haklısın. Aşağıdakilerin tümü eşdeğerdir: setTimeout (function () {}, 10000); VEYA setTimeout (yeni Function (), 10000); VEYA setTimeout (Function (), 10000); VEYA setTimeout (Fonksiyon, 10000); çünkü Javascript dilbilgisi ve Function yapıcı uygulaması bu yapılara izin verir.
Alan CS

5
ES6'da veya babel veya başka bir aktarıcı kullanarak (( )=>{};)teknik olarak Pure JS ve function () {}eşdeğerinden çok daha kısa ama tam olarak eşdeğer.
Ray Foss

2
Programımdaki hata ayıklama kodunu verimli bir şekilde kapatmak için işlem gerektirmeyen bir yapı bulmakla ilgileniyordum. C / C ++ 'da makrolar kullanırdım. Fn'mi Function.prototype'a atamayı test ettim ve zamanını belirledim, sonuçları işlevin içinde hemen dönecek bir if ifadesine sahip olmakla karşılaştırdım. Ayrıca bunları, işlevi döngüden tamamen kaldırmanın sonuçlarıyla da karşılaştırdım. Ne yazık ki, Function.prototype hiç iyi performans göstermedi. boş bir işlevi çağırmak performansta çok daha üstündü, hatta geri dönmek için basit 'eğer' testi ile işlevi çağırmaktan bile daha hızlıydı.
bearvarine

73

En özlü ve ölçülebilir noop bir olan boş ok fonksiyonu : ()=>{}.

Ok işlevleri , IE dışındaki tüm tarayıcılarda yerel olarak çalışır ( gerekirse bir babel dönüşümü vardır ): MDN


()=>{} vs. Function.Prototype

  • ()=>{}olduğu % 87 daha hızlı daha Function.prototypeChrome 67.
  • ()=>{}olduğu % 25 daha hızlı daha Function.prototypeFirefox 60.
  • ()=>{}olduğu % 85 daha hızlı daha Function.prototypeEdge (2018/06/15) .
  • ()=>{}olan % 65 daha az kodu daha Function.prototype.

Aşağıdaki test Function.prototype, önyargı vermek için ok işlevini kullanarak ısınır , ancak ok işlevi açık bir şekilde kazanır:

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!`)


1
Bazı seçenekleri karşılaştırmak için bir jsPerf testi oluşturdum: noop işlevi . Görünüşe göre Firefox 54'te tüm alternatifler eşdeğer görünüyor; Chromium 58'de Function.prototypebüyük ölçüde yavaştır, ancak diğer seçeneklerin hiçbirinin kesin bir avantajı yoktur.
Lucas Werkmeister

_=>{}bir karakter eksiktir ve aynı şeyi yapar.
Ross Attrill

@RossAttrill * benzer şey - _=>{}tek bir parametreye sahiptir. Birisi TypeScript'i oldukça katı bir yapılandırmayla kullanıyorsa, bu derlenmez. Eğer onu çağırırsanız, IDE'niz muhtemelen herhangi bir tipte olabilecek tek bir parametreyi kabul ettiğini söyleyecektir (hem JavaScript hem de özellikle vscode'da TypeScript).
cchamberlain

15

burada başarmaya meyilli olduğunuz şey yanlıştır. Üçlü ifadeler tam bir ifade olarak değil , yalnızca ifade olarak kullanılacaktır, bu nedenle sorunuzun cevabı şu şekildedir:

önerilerinizden hiçbirini yapmayın:

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

o zaman kod kolayca anlaşılabilir, okunabilir ve alabildiği kadar verimli olur.

Basit olabildiği halde neden daha zor hale getirelim?

Düzenle:

Öyleyse, bir "işlem yok" komutu temelde daha düşük bir kod yapısını mı gösterir?

Benim fikrimi kaçırıyorsun. Yukarıdakilerin tümü üçlü ifade ile ilgilidir x ? y : z.

Ancak, Javascript gibi daha yüksek seviyeli dillerde işlem yok komutu bir anlam ifade etmez.

Genellikle, montaj veya C gibi daha düşük seviyeli dillerde, işlemcinin zamanlama amacıyla tek bir talimat için hiçbir şey yapmamasını sağlamanın bir yolu olarak kullanılır.

JS tek yapmanız olsun 0;, null;, function () {};veya boş bir deyimi, onu okurken o Interpretor tarafından göz ardı edilecektir büyük şansı vardır, ama önce o yorumlanır alır, böylece sonunda, sadece program yapacağız çok küçük bir süre ile daha yavaş yüklendi. Nota Bene : Bunu varsayıyorum, çünkü yaygın olarak kullanılan herhangi bir JS tercümanıyla ilgilenmiyorum ve her tercümanın kendi stratejisi olma ihtimali var.

$.noop()Veya gibi biraz daha karmaşık bir şey kullanmanız durumunda var foo = function () {}; foo(), yorumlayıcı, işlev yığınınızın birkaç baytını ve birkaç döngüyü bozacak gereksiz bir işlev çağrısı yapabilir.

Var $.noop()olacak gibi bir işlevi görmemin tek nedeni , bazı olay işlevine, geri aramayı çağıramazsa bir istisna atacak bir geri arama işlevi vermeye devam edebilmektir. Ama sonra, bu zorunlu olarak vermeniz gereken bir işlevdir ve ona noopisim vermek iyi bir fikirdir, bu yüzden okuyucularınıza (ve 6 ay içinde bu olabilirsiniz) bilerek boş bir işlev verdiğinizi söylüyorsunuz.

Sonuçta, "aşağı" veya "üstün" kod yapısı diye bir şey yoktur. Aletlerinizi kullanma şeklinizde ya haklısınız ya da yanlışsınız .. Örneğiniz için üçlü kullanmak, vidalamak istediğinizde çekiç kullanmak gibidir. İşe yarayacak, ama o vidaya bir şey asabileceğinden emin değilsin.

"Alt" veya "üstün" olarak kabul edilebilecek şey, kodunuza koyduğunuz algoritma ve fikirlerdir. Ama bu başka bir şey.


1
Öyleyse, bir "işlem yok" komutu temelde daha düşük bir kod yapısını mı gösterir?
kmiklas

3
@kmiklas: assembler dışında bir NOOP için meşru bir ihtiyaç bulduğumu söyleyemem.
Matt Burland

@zmo: Yorumlarınızın üçlü ifadeyle nasıl ilişkili olduğuna dair düşüncenizi anlıyorum; Görünüşe göre herkes, bunun "İşlem Yok" işlevine yapılan çağrının açıklayıcı bir örneği olduğu yönündeki düşüncemi kaçırmış görünüyor.
kmiklas

1
Elbette işlemsiz bir özelliği istemek / buna ihtiyaç duymak için sebepler var. Bir şey hakkında 12 saniyelik derin düşüncenize dayanarak geniş genellemeler yapmayın. JavaScript, işlevleri değişkenler olarak tamamen kontrol edilebilir hale getiren bir dildir. Açık bir test olmadan bir işlevi devre dışı bırakmanız gerektiğini varsayalım. Bu bunun için mükemmel olur. Hata ayıklama ifadesi gibi sık görünen bir işleviniz varsa, işlev her göründüğünde bazı değişkenleri test etmek için fazladan kod eklemek yerine işlevi işlemsiz olarak yeniden atayarak bu işlevi kapatmanız güzel olur. .
bearvarine

2
@bearvarine, hakkımda sahip olduğunuz yüksek fikir için teşekkür ederim :-D. Yorumunuzda kesinlikle haklısınız, ancak bu gerçekten kod tasarımı için değil, sadece bir hack kullanarak mockup tasarımı. Tarif ettiğiniz
şeye

7

Sanırım jQuery noop()çoğunlukla istenen işlev mevcut olmadığında varsayılan bir işlev sağlayarak kodun çökmesini önlemeyi amaçlıyor. Örneğin, aşağıdaki kod örneği dikkate alındığında, tanımlanmamışsa $.noopseçilir fakeFunctionve sonraki çağrının fnkilitlenmesini önler :

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

Ardından, noop()kodunuzun her yerine aynı boş işlevi birden çok kez yazmaktan kaçınarak bellekten tasarruf etmenizi sağlar. Bu arada, (jeton başına 6 bayt kaydedildi) $.noopdeğerinden biraz daha kısa function(){}. Dolayısıyla, kodunuz ile boş işlev kalıbı arasında bir ilişki yoktur. Kullanım null, falseya 0da dilerseniz, sizin durumunuzda herhangi bir yan etki olacaktır. Ayrıca, bu kodun ...

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

... hiçbir zaman işlevi çağırmayacağınız için tamamen yararsızdır ve bu ...

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

... boş bir işlevi çağırdığınız için daha da yararsızdır, ki bu tam olarak ...

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

Üçlü ifadeyi ifne kadar yararsız olduğunu görmek için bir ifadeyle değiştirelim:

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

Basitçe yazabilirsiniz:

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

Veya daha da kısa:

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

Sonunda sorunuzu yanıtlamak için, sanırım hiçbir zaman yazılmayan "geleneksel bir işlem yok".


1
Ancak bazen bir işlev sağlamanız gerekir. Örneğin sözler söz konusu olduğunda (fn, fn) bazen ikinci işlevi sağlamak istersiniz, ancak ilk işlevi değil. bu nedenle yer tutucu için bir şeye ihtiyacınız var ...mypromise.then($.noop, myErrorhandler);
John Henckel

3

Kullanırım:

 (0); // nop

Bu çalıştırmanın yürütme zamanını şu şekilde test etmek için:

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

sonuç: işaret: 0.000 ms

Kullanımı Boolean( 10 > 9)basitçe ( 10 > 9)hangi dönüşe indirgenebilir true. Tam olarak beklediğim tek bir işleneni kullanma fikrini ortaya çıkardığımda (0);geri dönecek false, ancak konsolda bu testi gerçekleştirerek gözden geçirilebileceği gibi argümanı geri döndürüyor.

> var a = (0);
< undefined
> a
< 0

1
bunu deneyen birçok kişi alacakargument 0 is not a function
Code Whisperer

4
Sadece 0 atıyorsunuz. IMO noop, undefinedsonuçla değerlendirilen bir işlev olmalıdır .
cchamberlain

1
Bu ifade nasıl (0); 0 atama ?, var ve eşittir işareti nerede? (0) 'ın önünde işlev adı yok, bu yüzden bunun nasıl bir argüman olabileceğini anlamıyorum? typeof ((0)) denerseniz, sayı olarak geri gelir. Soruyu cevapladığımda, bir NOP'yi taklit etmek için kullandığım bir ifade sunuyordum, ancak cevabımı basitçe kullanmak için değiştirmeye hazırım; boş bir ifadeyi temsil etmek için
Eggs

1
Sanırım (0); OP'nin sorusu için kabul edilebilir bir çözümdür. Bence insanlar bu sayfayı hiçbir şey yapmayan bir ifade yerine hiçbir şey yapmayan bir işlev ararken buldukları için kafaları karışıyor. OP başlangıçta function(){}bir çözüm önererek yardımcı olmuyor . Çağrı (0)()neden olurTypeError: 0 is not a function
Benjamin

Ben bahsediyordum var a = (0);. İşlemsizlik hafızayı değiştirmemelidir ve sizin atama örneğiniz tam da bunu yapar. (0)Kendi başına bir işe yaramaz hayır-op düşünülebilir (JavaScript bunlar sonsuz sayıda vardır kadar özel burada örnek kılan şey yok).
cchamberlain

2

Function.prototypeOver kullanmanın kesinlikle bir problemi veya performans cezası yoktur () => {}.

Ana faydası, Function.prototypeher seferinde yeni bir anonim işlevi yeniden tanımlamaktan ziyade, tek bir işlevin olmasıdır. Function.prototypeVarsayılan değerleri tanımlarken ve hafızaya alırken, size asla değişmeyen tutarlı bir nesne işaretçisi verdiğinden, işlemsiz bir işlem kullanmak özellikle önemlidir .

Ben önereceğim nedeni Function.prototypeziyade Functiononlar aynı değiliz yüzünden mi:

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

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

Ayrıca, diğer yanıtlardan alınan ölçütler yanıltıcıdır . Aslında, karşılaştırmayı nasıl yazdığınıza ve çalıştırdığınıza bağlı olarak Function.prototypedaha hızlı performans () => {}gösterir:

JS kıyaslamalarına güvenemezsiniz << Özellikle bu soru için kıyaslama yapmak.

Kodunuzu karşılaştırmalardan biçimlendirmeyin; bakımı yapılabilecek her şeyi yapın ve uzun vadede nasıl optimize edileceğini tercümanın bulmasına izin verin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.