JavaScript'te “! -” ne yapar?


376

Bu kod parçası var ( bu sorudan alınmıştır ):

var walk = function(dir, done) {
    var results = [];

    fs.readdir(dir, function(err, list) {
        if (err)
            return done(err);

        var pending = list.length;

        if (!pending) 
            return done(null, results);

        list.forEach(function(file) {
            file = path.resolve(dir, file);
            fs.stat(file, function(err, stat) {
                if (stat && stat.isDirectory()) {
                    walk(file, function(err, res) {
                        results = results.concat(res);

                        if (!--pending)
                            done(null, results);
                    });
                } else {
                    results.push(file);

                    if (!--pending) 
                        done(null, results);
                }
            });
        });
    });
};

Onu takip etmeye çalışıyorum ve sanırım sonuna kadar yakın olanlar dışında her şeyi anlıyorum !--pending. Bu bağlamda, bu komut ne yapar?

Düzenleme: Tüm diğer yorumları takdir ediyorum, ancak soru birçok kez cevaplandı. Yine de teşekkürler!


222
Bir sonraki kişiyi kodu korumak için karıştırmanın harika bir yolu.
Eric J.

240
!~--[value] ^ trueBen bu "iş güvenliği" gibi kodu
arıyorum

63

36
@ TbWill4321 Kod incelemesi yapıyordum, iş güvenliğinin tam tersi olurdu.
corsiKa

8
Değişken adı markaları ile birleştirilen işleçler çok kötü değil. Tecrübeli herhangi bir Javascript programcısı, ne yaptığını bilmek için birkaç saniyeden fazla süreye ihtiyaç duymaz.
Christiaan Westerbeek

Yanıtlar:


537

! bir değeri tersine çevirir ve size tam tersi boole verir:

!true == false
!false == true
!1 == false
!0 == true

--[value] bir sayıdan bir (1) çıkartır ve ardından üzerinde çalışılacak sayıyı döndürür:

var a = 1, b = 2;
--a == 0
--b == 1

Bu nedenle, !--pendingbeklemede olanı çıkarır ve sonra doğruluk / falsy değerinin tersini döndürür (ister olmasın 0).

pending = 2; !--pending == false 
pending = 1; !--pending == true
pending = 0; !--pending == false

Ve evet, ProTip'i takip edin. Bu, diğer programlama dillerinde yaygın bir deyim olabilir, ancak çoğu bildirimsel JavaScript programlama için bu oldukça yabancı görünüyor.


623
ProTip ™: Bunu asla kodunuzda yapmayın, çok saçma.
Naftuli Kay

17
Bu --sadece değişkenler üzerinde etkili olduğu anlamına gelmez ; genel olarak değerlere uygulayamazsınız.
deltab

10
@deltab: validSimpleAssignmentTargets, kesin olarak. Bu tanımlayıcı referansları ve özellik referanslarını içerir.
Bergi

19
--0ve --1çalışmaz. Sayısal değişmez değerler geçerli sol taraftaki ifade değil
PSWai

7
@Pharap: Ah, o i > -1şeyi ayrıştırmaktan daha fazla sorunum var i--(ve unuttun mu? i = init() - 1) Deyimler bunun içindir… ve her programcı bunları öğrenmelidir.
Bergi

149

Bu özel bir operatör değil, birbiri ardına 2 standart operatör:

  1. Bir önek azalması ( --)
  2. Mantıksal değil ( !)

Bu pendingazalır ve sıfır olup olmadığını test eder.


8
Bu konuda kesinlikle yeniyim, ama bu neden kullanmaktan daha üstün if(pending === 1)?
Kieran E

46
@KieranE, "okunabilirlik kraldır" kuralını tamamen ihlal eden steno değil.
Ryan

23
@KieranE Üstün olmakla ilgili değil, farklı. Değişkeni değiştirir (1 azaltır) ve test etmek için yeni değeri kullanır
Amit

7
@KieranE, eşdeğerdir if( pending === 1 ) { done... } else { pending = pending - 1; }.
CompuChip

7
@CompuChip Aslında - beklemede her durumda yapılacak gibi görünüyor, bu nedenle kod daha çok benzer: if (! Bekleyen) {--pending; vb.} else {- beklemede; }} Bu geliştirici.mozilla.org/
Paul Russell

109

Bazı yanıtlar bu komutun ne yaptığını açıklar , ancak neden bu şekilde yapıldığını açıklamaz.

C dünyasından geliyorum ve gerçekten düşünmeden !--pending"geri sayım pendingve sıfır olup olmadığını kontrol et " olarak okuyorum . Benzer dillerdeki programcıların bilmesi gerektiği bir deyimdir.

İşlev readdir, toplu olarak "girişler" olarak adlandıracağım dosya ve alt dizinlerin bir listesini almak için kullanır .

Değişken pending, bunlardan kaç tanesinin işleneceğini takip eder. Liste uzunluğu olarak başlar ve her giriş işlenirken sıfıra doğru aşağı doğru sayar.

Bu girişler sıra dışı işlenebilir, bu nedenle basit bir döngü kullanmak yerine geri sayım yapmak gerekir. Ne zaman bütün kayıtlar işlendikten geri arama doneBu gerçeğin orijinal arayan bildirmek için çağrılır.

İlk çağrıda , bir değer döndürmek istediğimiz için değil, sadece işlevin o noktada yürütmeyi durdurmasını istediğimiz için doneeklenir return. returnAlternatifi bırakmak ve koymak için daha temiz bir kod olurdu else.


13
@Bergi, C dünyasında iyi bilinen bir deyimdir, ancak deyimsel Javascript değildir . Belirli bir alt ifade için, farklı ekosistemler, orada 'nasıl yapılır', farklı, uyumsuz deyimlere sahip olacaktır. 'Yabancı' dillerden deyimler kullanmak oldukça kötü bir kod kokusudur.
Peteris

3
@Peteris: Azaltma operatörüne sahip tüm C benzeri dillerde bir deyimdir. Tabii ki, bazen bir dilde farklı, daha iyi yollar vardır, ancak JS'nin özel sayma deyimleri olduğunu sanmıyorum.
Bergi

6
Javascript topluluğunun, Douglas Crockford gibi etkili liderler de dahil olmak üzere, tekli artış ve azaltma operatörlerinden tamamen kaçınmayı savunan önemli bir kısmı var . Burada onların doğru olup olmadıklarını tartışmayacağım; Amacım sadece tartışma var olduğu için kodun !--pendingbirçok linter ve stil yönergesinde başarısız olacağını belirtmek . Muhtemelen deyimsel olmadığını söylemek için yeterli (alternatifin daha iyi olup olmadığına bakılmaksızın).
GrandOpener

3
@GrandOpener "Deyimsel", "ana dili İngilizce olan kişiler tarafından yaygın olarak anlaşılan bir ifade" anlamına gelir. Tahmin, C benzeri dil kullanıcıları için kesinlikle iyi anlaşılmıştır ve uzantı olarak "! (- x)" de öyle. Bir şey kullanmanın iyi bir fikir olup olmadığı tamamen idiyomatik olandan ayrı bir sorudur. (Örneğin, kodunuza dahil edilmesinin listede "Şehvet" ve "Cinayet" arasında bir yere düştüğüne dair sık ​​sık dile getirilen görüşe rağmen, "goto" nun ne yaptığını anlamayan herhangi bir dilin birçok programcısıyla karşılaşacağınızdan şüpheliyim. sekiz ölümcül günahın.)
jmbpiano

3
En C # ve Java dönüştürmek yok çünkü @Pharap intiçin booldolaylı ve kullanımı ile hiçbir ilgisi vardır !--.
Agop

36

Bu bir steno.

! değil".

-- bir değeri azaltır.

Dolayısıyla !--, bir değerin azaltılmasının sonucunu reddetmekten elde edilen değerin yanlış olup olmadığını kontrol eder.

Bunu dene:

var x = 2;
console.log(!--x);
console.log(!--x);

Birincisi yanlıştır, çünkü x değeri 1 olduğundan, ikincisi doğrudur, çünkü x değeri 0'dır.

Yan not: !x--önce x'in yanlış olup olmadığını kontrol eder ve sonra azaltır.


RE yan notu - emin misin? !Ön düzeltme daha düşük önceliğe sahipken, ön düzeltme daha yüksek önceliğe sahip gibi görünüyor . JavaScript Operatörü önceliği
Dannnno

2
Evet. (Deneyin var x = 2; console.log(!x--); console.log(!x--); console.log(!x--);). Düzeltme işlemi --ilk olarak yürütülebilse de, dönüş değeri azalmadan önce değişkenin değeridir ( Azaltma Ayırıcı ).
Lucas

Bence " !--bir değeri azaltmanın sonucunun olumsuzluğunu döndürür " demek istediniz. Sadece dış kod, örneğin console.log()içeriğinin doğru olup olmadığını kontrol eder.
mareoraft

31

!JavaScript DEĞİL işleci

--bir azaltma öncesi operatörüdür. Yani,

x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
          // which makes the condition to be true

8
WTH bir "sahte ifade" midir?
Bergi

5
@Bergi Aslında bunun ne anlama geldiğini bildiğinizi varsayıyorum, ancak bilmiyorsanız (veya başka biri bilmiyorsa) , bu kavramla (Python gibi) diğer dillere de iyi bir şekilde tercüme eden bir JavaScript açıklamasıdır .
Dannnno

1
@Pharap bu benim cevabım değil, bu yüzden dokunmayacağım.
Dannnno

2
@Dannnno: Peki falsy değerlerinin ne olduğunu ve hangi ifadelerin olduğunu biliyorum ve bu yüzden JS'de "falsy ifadesi" gibi bir şey olmadığını biliyorum. Bunun mantık terimiyle ilgili olmadığını varsayıyorum .
Bergi

1
--Operatörün bir sabitle nasıl çalışabileceğini anlamıyorum ... belki --xbunun yerine --0?
SJuan76

24
if(!--pending)

anlamına geliyor

if(0 == --pending)

anlamına geliyor

pending = pending - 1;
if(0 == pending)

4
Ve o kod yazmak için net bir yoldur. Tabii ki, if(0 == pending)yazım hatası potansiyeli nedeniyle tercih ederim . if(0 = pending)bir sözdizimi hatasıdır. if(pending = 0)bitmiş kodda kafa karıştırıcı davranışlara neden olacak bir ödevdir.
Theo Brinkman

3
@TheoBrinkman: aslında if(0 = pending)bir sözdizimi hatası değil - iyi ayrıştırılıyor - ancak atanamadığı için bir Referans Hatası 0(ref ECMA-262 (6. baskı) sn 12.14.1).
hmakholm Monica

13

Bu, yerinde olmayan ön azaltıcı tarafından takip edilen operatör değildir.

Yani pending, 1 değerine sahip bir tam sayı olsaydı :

val = 1;
--val; // val is 0 here
!val // evaluates to true

11

Sadece bir azalır pendingve mantıksal tamamlayıcısını (olumsuzlama) alır. 0'dan farklı herhangi bir sayının mantıksal tamamlayıcısı, false0 için true.


Lütfen "negate" ifadesinin booleans değerlerinden farklı bir anlamı olduğuna dikkat edin
Bergi

1
Pekala, farklı bir terim kullanacağım. Bu daha iyi olsa emin değilim.
MinusFour

11

açıklama

Bu 2 operatör, a !ve a--

!--x 

Yani, --x'i 1 azaltır, o zaman !x şimdi 0 (veya NaN ...) ise true değerini, değilse false değerini döndürür. Bu deyimi "x değerini azaltıyoruz ve bu sıfır yaparsa ..." gibi bir şey okuyabilirsiniz.

Daha okunabilir hale getirmek istiyorsanız, şunları yapabilirsiniz:

var x = 1
x = x - 1   
if(!x){ //=> true
    console.log("I understand `!--` now!") 
}
x //=> 0

Denemek:

/* This is an example of the above, you can read this, but it is not needed for !-- */function interactive(a){$("span.code").keydown(function(e){if(13==(e.keyCode||e.which)){var t=$(this);t.clone().html("code").insertAfter(t.next().next()).show().focus().after(template.clone().removeClass("result-template").show()).next().after("<br>"),interactive(),e.preventDefault()}}).keyup(function(e){13!=(e.keyCode||e.which)&&run()})}var template=$(".result-template").hide(),code=$("span.code");code.attr("contenteditable","true").each(function(e,t){template.clone().removeClass("result-template").insertAfter(t)}),interactive(),$.fn.reduce=[].reduce;function run(){var b=!1,context={};$("span.code").each(function(){var a=$(this),res=a.next().show().removeClass("error");try{with(context)res.html(b?"":"  //=> "+eval(a.text()))}catch(e){b=e,res.html("  Error: "+b.message).addClass("error")}})};run();
/* This is an example of the above, you can read this, but it is not needed for !-- */span.result.error{display:block;color:red}.code{min-width:10px}body{font-family:Helvetica,sans-serif}
<!-- This is an example of the above, you can read this, but it is not needed for `!--` --><span class="result result-template"> //=> unknown </span> <h2>Edit This Code:</h2><code><span class="code">x = 1</span><br><span class="code">!--x</span><br><span class="code"> x </span><br></code> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Fiddle (Kodu Deneyin)


8

Buradaki asıl sorun, iki operatör !ile arasındaki boşluk olmaması --.

İnsanların neden !operatörlerinden sonra bir boşluk kullanamayacağınızı neden kafalarına aldıklarını bilmiyorum . Bence bu, sağduyu yerine mekanik boşluk kurallarının katı bir şekilde uygulanmasından kaynaklanıyor. Gördüğüm hemen hemen her kodlama standardı, tekli operatörlerden sonra boşlukları yasaklıyor, ama neden?

Bu alana açıkça ihtiyaç duyduğunuz bir durum olsaydı , bu bir tane.

Şu kod parçasını düşünün:

if (!--pending)
    done(null, results);

Sadece edilir !ve --birlikte püre, o var (çok onlara karşı çarptı. Neyin neye bağlı olduğunu söylemek zor değil.

Biraz daha fazla boşluk kodu çok daha net hale getirir:

if( ! --pending )
    done( null, results );

Elbette, "parenlerde boşluk yok" ve "tekli bir operatörden sonra boşluk yok" gibi mekanik kurallara alışkınsanız, bu biraz yabancı görünebilir.

Ancak ekstra boşlukların nasıl ififade ve ifadenin çeşitli bölümlerini nasıl ayırdığına ve ayırdığına bakın : Sahip oldunuz --pending, bu yüzden --açıkça kendi operatörü ve yakından bağlı pending. (Azalan pendingve azalan sonucu döndürür.) O zaman ondan !ayrıldınız, bu yüzden açıkça ayrı bir operatör, sonucu reddediyor. Sonunda, bir ifade yapmak için tüm ifadeyi aldınız if(ve )çevreliyorsunuz if.

Ve evet, aralarında boşluk kaldırıldı ifve (çünkü ( aittir için if. Bu (, (!--orijinalde olduğu gibi bir tür sözdiziminin bir parçası değildir (, ififadenin sözdiziminin if parçası ise .

Buradaki boşluk , bazı mekanik kodlama standartlarına uymak yerine anlamı iletmeye hizmet eder .


1
Beyaz boşluklu sürüm benim için daha okunaklı. Soruyu ilk gördüğümde !--bilmediğim bir javascript operatörü olduğunu varsaydım . Neden daha açık hale getirmek için parantez kullanmıyorsunuz? if(!(--pending))
emory

1
Stil kılavuzu yok ++veya kullanımını yasakladığımı biliyorum-- , ancak birçoğu önek operatörü ve zorunlu olmayan parantez gibi önemli olmayan boşlukların kullanılmasını yasaklıyor . !

1
Tekli operatörlerden sonraki boşluk, çalıştığı ifadeden ayırdığı için önerilmez. Birlikte okunmasını istersiniz ... en azından imho
aldrin
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.