JavaScriptで「!-」は何をしますか?


376

私はこのコードを持っています(この質問から取られた):

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

私はそれを追跡しようとしています、そしてそれが言っている終わり近くを除いてすべてを理解していると思い!--pendingます このコンテキストでは、そのコマンドは何をしますか?

編集:私はそれ以上のコメントに感謝しますが、質問は何度も答えられました。とにかくありがとう!


222
これは、次の人がコードを保守するのを混乱させる素晴らしい方法です。
エリックJ.

240
!~--[value] ^ trueこのようなコードを「ジョブセキュリティ」と呼んでいます
TbWill4321 '16


36
@ TbWill4321コードレビューを行っている場合、それはジョブセキュリティの正反対です。
corsiKa

8
変数名と組み合わせる演算子は、それほど悪くありません。熟練したJavascriptプログラマーであれば、何をするかを知るのに数秒も必要ありません。
Christiaan Westerbeek、2015

回答:


537

! 値を反転し、反対のブール値を与えます:

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

--[value] 数値から1を引いて、処理する数値を返します。

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

したがって、!--pending保留中の値から1を減算し、その真偽値の反対を返します(それがそうであるかどうかに関係なく0)。

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

はい、ProTipに従ってください。これは他のプログラミング言語では一般的なイディオムかもしれませんが、ほとんどの宣言型JavaScriptプログラミングでは、これはかなり異質に見えます。


623
ProTip™:コードでこれを行わないでください。ばかげています。
Naftuli Kay、2015

17
これは--変数のみに作用することについては触れていません。一般的に値に適用することはできません。
deltab 2015

10
@deltab:validSimpleAssignmentTargets、正確には。これには、識別子の参照とプロパティの参照が含まれます。
Bergi

19
--0動作し--1ません。数値リテラルは有効な左側の式ではありません
PSWai

7
@Pharap:ええと、私はそのi > -1ことを解析するのに苦労しますi--(そして、あなたが忘れていたi = init() - 1)。それがイディオムの目的です…そしてすべてのプログラマーはそれらを学ぶべきです。
Bergi

149

これは特別な演算子ではなく、次の2つの標準演算子です。

  1. 接頭辞減分(--
  2. 論理否定(!

これによりpending、デクリメントされ、ゼロかどうかがテストされます。


8
私は間違いなくこれに新しいですが、なぜこれは使用するより優れているのif(pending === 1)ですか
Kieran E

46
@KieranE、そうではありません。「読みやすさは王様である」というルールを完全に破るのは略記です。
ライアン

23
@KieranEそれは優れているということではなく、違います。変数を変化させ(1だけ減らす)、新しい値を使用してテストします
Amit

7
@KieranE、これはと同等if( pending === 1 ) { done... } else { pending = pending - 1; }です。
CompuChip 2015

7
@CompuChip実際には--pendingはどのような場合でも行われるように見えるため、コードは次のようになります。if(!pending){--pending; etc.} else {-保留中; etc.}これはdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…に
Paul Russell

109

多くの回答がこのコマンドの機能を説明してますが、ここでそのように実行される理由は説明されていません。

私はCの世界出身で、何も考えずに!--pending「カウントダウンしてpendingゼロか確認」と読んでいます。類似言語のプログラマが知っておくべきイディオムです。

この関数はreaddir、ファイルとサブディレクトリのリストを取得するために使用します。これらをまとめて「エントリ」と呼びます。

変数pendingは、これらのうち処理されていない残りの数を追跡します。リストの長さから始まり、各エントリが処理されるにつれてゼロに向かってカウントダウンします。

これらのエントリは順不同で処理される可能性があるため、単純なループを使用するのではなく、カウントダウンする必要があります。ときに、すべてのエントリが処理されたコールバックは、doneこの事実を元の発信者に通知するために呼び出されます。

最初の呼び出しでdoneは、が先頭に追加されreturnます。これは、値を返す必要があるためではなく、単にその時点で関数の実行を停止するためです。を削除しreturn、代替コードをに配置するのは、よりクリーンなコードelseでした。


13
@BergiこれはCの世界ではよく知られた慣用句ですが慣用的なJavaScript ではありません。与えられた部分式について、エコシステムが異なれば、互換性のないさまざまなイディオムがさまざまに存在し、そこでどのように「実行される」かを示します。「外国の」言語のイディオムを使用すると、コードの臭いがかなり悪くなります。
Peteris

3
@Peteris:それは、デクリメント演算子を持つすべてのC言語のような言語の慣用句です。もちろん、言語で利用できる別のより良い方法があることもありますが、JSが特別なカウントイディオムを持っているとは思いません。
Bergi

6
Douglas Crockfordなどの有力なリーダーを含む、Javascriptコミュニティの重要な部分があり、単項インクリメントおよびデクリメント演算子を完全に回避することを提唱しています。それらが正しいかどうかについては、ここでは議論しません。私の意図は、論争が存在するので、コードのようなもの!--pendingが多くのリンターとスタイルガイドラインに失敗することを指摘することだけです。(代替案が「より良い」かどうかに関係なく)おそらく私はそれがおそらく慣用的ではないと言うには十分です。
GrandOpener 2015

3
@GrandOpener「イディオマティック」とは、「ネイティブスピーカーが一般的に理解する表現」を意味します。プリデクリメントは、間違いなく C-ような言語のユーザーによく理解して、拡張子によって、そうです!「( - x)は」。何かを使用することがGoodIdea®であるかどうかは、それがどれほど慣用的であるかとはまったく別の問題です。(たとえば、コードにそれを含めることはリストの「欲望」と「殺人」の間にあるという頻繁に表明された意見にもかかわらず、「goto」が何をするかを理解していない任意の言語の多くのプログラマーに出くわすことを強く疑います8つの大罪のうちの1つ)
jmbpiano

3
@Pharapこれは、C#とJavaが暗黙的に変換さintれずbool、の使用法とはまったく関係がないためです!--
Agop 2015

36

略記です。

! ではありません"。

-- 値を減らします。

その!--ため、値をデクリメントした結果を否定することで得られた値がfalseかどうかを確認します。

これを試して:

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

xの値が1であるため、1つ目はfalseです。xの値が0であるため、2つ目はtrueです。

補足: !x--xがfalseかどうかを最初にチェックしてから、デクリメントします。


サイドノートをRE-よろしいですか?!プレフィックスの優先順位は低くなりますが、ポストフィックスの優先順位はよりも高いようです。JavaScript演算子の優先順位
Dannnno 2015

2
はい。(お試しくださいvar x = 2; console.log(!x--); console.log(!x--); console.log(!x--);)。Post-fix --が最初に実行される可能性がありますが、その戻り値は、デクリメントする前の変数の値です(Decrement Opperator)。
Lucas

!--「値を減らした結果の否定を返す」という意味だったと思います。などの外部コードのみがconsole.log()、その内容が真実かどうかをチェックします。
mareoraft 2015

31

!JavaScript NOT演算子です

--デクリメント前の演算子です。そう、

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

8
WTHは「虚偽の陳述」ですか。
Bergi

5
@Bergi私はあなたが実際にそれが何を意味するか知っていると思いますが、あなたが知らない場合(または他の誰も知らない場合)は、この概念を持つ他の言語(Pythonなど)にもある程度翻訳できるJavaScriptの説明を以下に示します
Dannnno

1
@Pharapそれは私の答えではないので、触れません。
Dannnno

2
@Dannnno:まあ、偽の値とは何か、ステートメントとは何かを知っているので、JSには「偽のステートメント」のようなものはありません。私はこれが論理用語を参照していないと思います。
Bergi

1
私はどのように理解していない--オペレータが一定で仕事ができる...多分あなたは意味--xの代わりに--0
SJuan76

24
if(!--pending)

手段

if(0 == --pending)

手段

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

4
そして、それはコードを書くための明確な方法です。もちろん、if(0 == pending)タイプミスの可能性があるので、私は好みます。 if(0 = pending)構文エラーです。 if(pending = 0)完成したコードで混乱する動作を引き起こす割り当てです。
Theo Brinkman、2015

3
@TheoBrinkman:実際にif(0 = pending)は構文エラーではありません-うまく解析されます-が0割り当てられないため、参照エラーです(ref ECMA-262(6th ed)sec 12.14.1)。
hmakholmがモニカに残った

13

これは、not演算子の後にインプレース事前宣言子が続きます。

したがってpending、値が1の整数の場合:

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

11

単にpending1 だけ減少し、その論理的な補数(否定)を取得します。0以外の数値の論理補数はfalseであり、0の場合はtrueです。


「否定」の意味はブール値とは異なることに注意してください
Bergi

1
では、別の用語を使用します。これがより良いかどうかはわかりません。
MinusFour 2015

11

説明

これはa !とaの2つの演算子です--

!--x 

したがって、--xを1ずつ減らし!、xが現在0(またはNaN ...)の場合はtrueを返し、そうでない場合はfalseを返します。このイディオムは、「xをデクリメントし、それがゼロになる場合は...」のように読むことができます。

読みやすくしたい場合は、次のことができます。

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

やってみて:

/* 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>

フィドル(コードを試す)


8

ここでの実際の問題は、2つの演算子!との間にスペースがないことです--

!オペレーターの後にスペースを使用できないことを人々が頭の中で理解する理由はわかりません。常識ではなく、機械的な空白のルールを厳格に適用することから来ていると思います。私が見たほとんどすべてのコーディング標準は、すべての単項演算子の後にスペースを禁止していますが、なぜですか?

明らかにそのスペースが必要なケースがあった場合、これは1つです。

次のコードを検討してください。

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

だけでなく、されている!--一緒につぶし、あなたはそれを持っています(、あまりにもそれらに対して放ちました。何が何に接続されているのかを判断するのが難しいのも不思議ではありません。

余白が少し増えると、コードがより明確になります。

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

もちろん、「括弧内にスペースなし」や「単項演算子の後にスペースなし」などの機械的な規則に慣れている場合、これは少し異質に見えるかもしれません。

しかし、どのように余分な空白グループとのさまざまな部分に分離見ifの文と式を:あなたが持っている--pendingので、--明らかに独自の演算子であるとに密接に結びついていますpending。(デクリメントpendingし、デクリメントした結果を返します。)次に、それを!分離して、明らかに異なる演算子にして、結果を否定します。最後に、あなたが持っているif()式全体を囲み、ifステートメントにします。

とに属しているため、ifとの間のスペースを削除しました。これは、いくつかの種類の一部ではない、元にあるように見えるよう、構文の構文の場合は一部(( if((!--(ifステートメント自体の。

ここの空白は、機械的なコーディング標準に従うのはなく、意味を伝えるために使用されます。


1
空白のバージョンは私には読みやすいです。私が最初に思った質問を見たとき、私!--は知らないjavascript演算子だと思いました。括弧を使用してさらに明示的にしないのはなぜですか?if(!(--pending))
エモリー、2015

1
私が使用して禁止を認識していませスタイルガイドません++--、しかし多くはないようにした後、非本質的なスペース使用禁止!接頭演算子、および非必須括弧を。

1
単項演算子の後の空白は、それが操作する式から分離されるため、お勧めしません。あなたはそれを一緒に読んでもらいたいです...少なくとも私見
アルドリン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.