380

ツールのヒントのjslint1 つは次のとおりです。

++--
(++インクリメント) および(--デクリメント) 演算子は、過度のトリッキーさを助長することにより、悪いコードに寄与することが知られています。それらは、ウイルスやその他のセキュリティの脅威を可能にするという点で、欠陥のあるアーキテクチャに次ぐものです。これらの演算子の使用を禁止する plusplus オプションがあります。

次のような PHP 構造体$foo[$bar++]がオフバイワン エラーを引き起こしやすいことはわかっていますが、ループを制御するための次の方法よりも優れた方法を見つけることができませんでした。

while( a < 10 ) do { /* foo */ a++; }

また

for (var i=0; i<10; i++) { /* foo */ }

" " と " "の構文がない、または異なる方法で処理するjslint類似の言語がいくつかあるため、それらを強調表示しているのでしょうか。++--++--

4

18 に答える 18

433

私の見解は、次のように、常に ++ と -- を 1 行で単独で使用することです。

i++;
array[i] = foo;

それ以外の

array[++i] = foo;

それ以上のものは、一部のプログラマーを混乱させる可能性があり、私の見解では価値がありません。インクリメント演算子の使用は慣用的であり、常に明確であるため、 for ループは例外です。

于 2009-06-09T17:30:00.693 に答える
263

私は率直に言って、そのアドバイスに混乱しています。私の一部は、それが JavaScript コーダーの (認識された、または実際の) 経験の欠如と関係があるのではないかと考えています。

サンプル コードを「ハッキング」するだけで、++ と -- で罪のない間違いを犯す可能性があることは理解できますが、経験豊富な専門家がそれらを回避する理由はわかりません。

于 2009-06-09T17:07:30.580 に答える
70

C には、次のようなことを行った歴史があります。

while (*a++ = *b++);

文字列をコピーするには、おそらくこれが彼が言及している過度の策略の源です。

そして、常に何の問題があります

++i = i++;

また

i = i++ + ++i;

実際にします。一部の言語では定義されていますが、他の言語では何が起こるかは保証されていません。

これらの例は別として、インクリメントに使用する for ループほど慣用的なものはないと思い++ます。場合によっては、別の条件をチェックする foreach ループまたは while ループを使用して回避できます。しかし、インクリメントを使用しないようにコードをゆがめるのはばかげています。

于 2009-06-09T17:17:55.123 に答える
50

JavaScript The Good Parts を読むと、Crockford によるforループの i++ の置き換えが i+=1 (i=i+1 ではない)であることがわかります。これは非常にクリーンで読みやすく、「トリッキー」なものに変形する可能性が低くなります。

Crockford は、自動インクリメントと自動デクリメントを許可しないことを jsLint のオプションにしました。アドバイスに従うかどうかを選択します。

私の個人的なルールは、オートインクリメントまたはオートデクリメントと組み合わせて何もしないことです。

C での長年の経験から、単純に使用し続ければバッファー オーバーラン (または範囲外の配列インデックス) が発生しないことを学びました。しかし、同じステートメントで他のことを行うという「過度にトリッキーな」慣行に陥ると、バッファー オーバーランが発生することがわかりました。

したがって、私自身のルールでは、 forループのインクリメントとして i++ を使用しても問題ありません。

于 2009-06-09T17:34:56.600 に答える
32

ループでは無害ですが、割り当てステートメントでは予期しない結果になる可能性があります。

var x = 5;
var y = x++; // y is now 5 and x is 6
var z = ++x; // z is now 7 and x is 7

変数と演算子の間の空白も、予期しない結果につながる可能性があります。

a = b = c = 1; a ++ ; b -- ; c; console.log('a:', a, 'b:', b, 'c:', c)

閉鎖では、予期しない結果も問題になる可能性があります。

var foobar = function(i){var count = count || i; return function(){return count++;}}

baz = foobar(1);
baz(); //1
baz(); //2


var alphabeta = function(i){var count = count || i; return function(){return ++count;}}

omega = alphabeta(1);
omega(); //2
omega(); //3

そして、改行の後に自動セミコロン挿入をトリガーします:

var foo = 1, bar = 2, baz = 3, alpha = 4, beta = 5, delta = alpha
++beta; //delta is 4, alpha is 4, beta is 6

プリインクリメント/ポストインクリメントの混同により、診断が非常に難しいオフバイワン エラーが発生する可能性があります。幸いなことに、それらも完全に不要です。変数に 1 を追加するより良い方法があります。

参考文献

于 2013-01-08T18:49:39.433 に答える
17

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

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[i++] = i++;
    a[i++] = i++;
    a[i++] = i++;

i++ は 2 回評価されるため、出力は (vs2005 デバッガーから)

    [0] 0   int
    [1] 0   int
    [2] 2   int
    [3] 0   int
    [4] 4   int

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

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[++i] = ++i;
    a[++i] = ++i;
    a[++i] = ++i;

出力が同じであることに注意してください。++i と i++ は同じものだと思うかもしれません。ではない

    [0] 0   int
    [1] 0   int
    [2] 2   int
    [3] 0   int
    [4] 4   int

最後に、このコードを検討してください

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[++i] = i++;
    a[++i] = i++;
    a[++i] = i++;

出力は次のとおりです。

    [0] 0   int
    [1] 1   int
    [2] 0   int
    [3] 3   int
    [4] 0   int
    [5] 5   int

したがって、それらは同じではありません。両方を混在させると、それほど直感的な動作にはなりません。for ループは ++ で問題ないと思いますが、同じ行または同じ命令に複数の ++ シンボルがある場合は注意してください

于 2009-06-09T17:30:01.207 に答える
16

私の見解では、「明示的は常に暗黙的よりも優れています」。ある時点で、この増分ステートメントと混同される可能性があるためですy+ = x++ + ++y。優れたプログラマーは、常に自分のコードを読みやすくします。

于 2011-04-26T13:26:40.933 に答える
16

インクリメント演算子とデクリメント演算子の「前」と「後」の性質は、それらに慣れていない人にとっては混乱する傾向があります。それは彼らがトリッキーになることができる1つの方法です.

于 2009-06-09T17:05:54.793 に答える
15

I've been watching Douglas Crockford's video on this and his explanation for not using increment and decrement is that

  1. It has been used in the past in other languages to break the bounds of arrays and cause all manners of badness and
  2. That it is more confusing and inexperienced JS developers don't know exactly what it does.

Firstly arrays in JavaScript are dynamically sized and so, forgive me if I'm wrong, it is not possible to break the bounds of an array and access data that shouldn't be accessed using this method in JavaScript.

Secondly, should we avoid things that are complicated, surely the problem is not that we have this facility but the problem is that there are developers out there that claim to do JavaScript but don't know how these operators work?? It is simple enough. value++, give me the current value and after the expression add one to it, ++value, increment the value before giving me it.

Expressions like a ++ + ++ b, are simple to work out if you just remember the above.

var a = 1, b = 1, c;
c = a ++ + ++ b;
// c = 1 + 2 = 3; 
// a = 2 (equals two after the expression is finished);
// b = 2;

I suppose you've just got to remember who has to read through the code, if you have a team that knows JS inside out then you don't need to worry. If not then comment it, write it differently, etc. Do what you got to do. I don't think increment and decrement is inherently bad or bug generating, or vulnerability creating, maybe just less readable depending on your audience.

Btw, I think Douglas Crockford is a legend anyway, but I think he's caused a lot of scare over an operator that didn't deserve it.

I live to be proven wrong though...

于 2010-09-27T13:18:07.783 に答える
14

++ または -- を回避する最も重要な理由は、演算子が値を返すと同時に副作用を引き起こし、コードについての推論を難しくすることです。

効率のために、私は次のことを好みます。

  • ++i戻り値を使用しない場合(一時的ではない)
  • 戻り値を使用する場合のi++ (パイプライン ストールなし)

私は Crockford 氏のファンですが、この場合は同意せざるを得ません。++iよりも解析するテキストが 25% 少なく、ほぼi+=1 間違いなくより明確です。

于 2012-03-07T13:51:00.083 に答える
10

インクリメントされた値の単純な戻り値を持つ他のいくつかよりも単純な別の例:

function testIncrement1(x) {
    return x++;
}

function testIncrement2(x) {
    return ++x;
}

function testIncrement3(x) {
    return x += 1;
}

console.log(testIncrement1(0)); // 0
console.log(testIncrement2(0)); // 1
console.log(testIncrement3(0)); // 1

ご覧のとおり、この演算子を結果に影響を与えたい場合は、return ステートメントでポスト インクリメント/デクリメントを使用しないでください。しかし、return は後置インクリメント/デクリメント演算子を「キャッチ」しません。

function closureIncrementTest() {
    var x = 0;

    function postIncrementX() {
        return x++;
    }

    var y = postIncrementX();

    console.log(x); // 1
}
于 2013-09-18T10:32:50.047 に答える
9

プログラマーは、使用する言語に精通しているべきだと思います。明確に使用してください。そして上手に使いましょう。彼らが使用している言語を人為的に不自由にするべきではないと思います。私は経験から話します。私はかつて、「複雑すぎる」という理由で ELSE を使用しなかった Cobol ショップの文字通り隣で働いていました。ばかげた還元。

于 2010-09-27T13:27:59.140 に答える
3

私の経験では、演算子がどのように機能するかを初めて学んだとき以外、++i または i++ が混乱を引き起こしたことはありません。演算子を使用できる言語で教えられている高校や大学のコースで教えられている最も基本的な for ループと while ループには不可欠です。私は個人的に、a ++が別の行にあるものよりも、以下のようなことをして見やすく読んでいることに気づきました。

while ( a < 10 ){
    array[a++] = val
}

結局のところ、それはスタイルの好みであり、それ以上のものではありません。より重要なことは、コードでこれを行う場合、同じコードで作業している他の人が従うことができ、同じ機能を異なる方法で処理する必要がないように、一貫性を保つことです。 .

また、Crockford は i-=1 を使用しているようですが、これは --i や i-- よりも読みにくいことがわかりました。

于 2016-06-22T17:26:39.620 に答える
2

既存の回答のいくつかで述べたように (これについてはコメントできません)、問題は x++ ++x が異なる値 (インクリメントの前と後) に評価されることです。これは明らかではなく、非常に混乱する可能性があります -その値が使用されている場合cdmckay は、インクリメント演算子の使用を許可することを非常に賢明に提案していますが、返された値が使用されない方法でのみ、たとえば独自の行でのみ使用されます。また、for ループ内に標準的な使用法を含めます (ただし、戻り値が使用されない 3 番目のステートメントのみ)。他に例が思いつきません。私自身「やけど」したので、他の言語にも同じガイドラインをお勧めします。

この厳しすぎるのは、多くの JS プログラマーが経験の浅いためであるという主張には同意しません。これはまさに「非常に賢い」プログラマーに典型的な書き方であり、より伝統的な言語や、そのような言語のバックグラウンドを持つ JS 開発者では、より一般的であると確信しています。

于 2011-01-27T06:53:51.877 に答える
2

私の 2 セントは、次の 2 つのケースでは避けるべきだということです。

1) 多くの行で使用される変数があり、それを使用する最初のステートメント (または最後、さらに悪い場合は途中) で変数を増減する場合:

// It's Java, but applies to Js too
vi = list.get ( ++i );
vi1 = list.get ( i + 1 )
out.println ( "Processing values: " + vi + ", " + vi1 )
if ( i < list.size () - 1 ) ...

このような例では、変数が自動インクリメント/デクリメントされていることを簡単に見逃したり、最初のステートメントを削除したりすることさえあります。つまり、非常に短いブロックでのみ使用するか、変数がブロック内の 2、3 の close ステートメントだけに現れる場所でのみ使用してください。

2) 同一文中の同一変数について ++ と -- が複数ある場合。次のような場合に何が起こるかを思い出すのは非常に困難です。

result = ( ++x - --x ) * x++;

試験やプロのテストでは、上記のような例について尋ねられます。実際、そのうちの 1 つに関するドキュメントを探しているときにこの質問に出くわしましたが、実際には、コードの 1 行についてそれほど考えることを強いられるべきではありません。

于 2016-09-30T10:40:02.577 に答える
0

Fortran は C に似た言語ですか? ++ も -- もありません。ループの書き方は次のとおりです。

     integer i, n, sum

      sum = 0
      do 10 i = 1, n
         sum = sum + i
         write(*,*) 'i =', i
         write(*,*) 'sum =', sum
  10  continue

インデックス要素iは、ループのたびに言語規則によってインクリメントされます。1 以外の値を増やしたい場合は、たとえば逆方向に 2 カウントします。構文は次のとおりです。

      integer i

      do 20 i = 10, 1, -2
         write(*,*) 'i =', i
  20  continue

Python は C に似ていますか? 範囲内包表記とリスト内包表記、およびその他の構文を使用して、インデックスをインクリメントする必要を回避します。

print range(10,1,-2) # prints [10,8.6.4.2]
[x*x for x in range(1,10)] # returns [1,4,9,16 ... ]

したがって、言語設計者は、正確に 2 つの代替案に関するこの初歩的な調査に基づいて、ユース ケースを予測し、代替構文を提供することで、++ と -- を回避できます。

Fortran と Python は、++ と -- を持つ手続き型言語よりも明らかにバグを引き付けませんか? 私には証拠がありません。

Fortran と Python が C に似ていると主張するのは、難読化されていない Fortran や Python の意図を 90% の精度で正しく推測できなかった C に堪能な人に会ったことがないからです。

于 2009-06-09T17:14:36.563 に答える