Po co unikać operatorów increment ( " ++ ") i decrement ( " -- " ) w JavaScript?

Jedna z porad dla narzędzia jslint to:

++ i --
The ++ (increment) and -- (decrement) operatorzy są znani z tego, że przyczyniają się do złego kodu przez zachęcanie do nadmiernej ściemy. Oni ustępują tylko wadliwej architekturze w celu umożliwienia wirusom i innym zagrożenia bezpieczeństwa. Jest plusplus opcja, która zakazuje korzystania z tych operatorzy.

Wiem, że PHP konstruuje tak jak $foo[$bar++] mA łatwo wynikać z błędów off-by-one, ale nie mogłem znaleźć lepszego sposobu na kontrolowanie pętli niż while( a < 10 ) do { /* foo */ a++; } lub for (var i=0; i<10; i++) { /* foo */ }.

Czy jslint je uwypukla, ponieważ istnieją podobne języki, w których brakuje składni" ++ "i" -- "lub obsługują je inaczej, czy też istnieją inne przesłanki unikania" ++ " i " --", których może mi brakować?

Author: Vikrant, 2009-06-09

16 answers

Moim zdaniem zawsze używam ++ i -- same w jednej linii, jak w:

i++;
array[i] = foo;

Zamiast

array[++i] = foo;

Cokolwiek poza tym może być mylące dla niektórych programistów i po prostu nie jest tego warte moim zdaniem. Pętle For są wyjątkiem, ponieważ użycie operatora inkrementacji jest idiomatyczne i dlatego zawsze jest jasne.

 420
Author: cdmckay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-08 11:47:19

Jestem szczerze zdezorientowany tą radą. Część mnie zastanawia się, czy ma to więcej wspólnego z brakiem doświadczenia (postrzeganego lub rzeczywistego) z koderami javascript.

Widzę, jak ktoś po prostu "hacking" na jakiś przykładowy kod może popełnić niewinny błąd z ++ I --, ale nie widzę powodu, dla którego doświadczony profesjonalista miałby ich unikać.

 261
Author: Jon B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 11:18:58

W C jest historia robienia takich rzeczy jak:

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

Aby skopiować ciąg znaków, być może jest to źródło nadmiernej sztuczki, o której mówi.

I zawsze jest pytanie, co

++i = i++;

Lub

i = i++ + ++i;
Właściwie tak. Jest zdefiniowany w niektórych językach, a w innych nie ma gwarancji, co się stanie.

Pomijając te przykłady, nie sądzę, że jest coś bardziej idiomatycznego niż pętla for, która używa ++ do inkrementacji. W niektórych przypadkach może uciec z pętli foreach, lub pętli while, który sprawdzał inny condition. Ale contorting kod, aby spróbować uniknąć za pomocą inkrementacji jest śmieszne.

 70
Author: Eclipse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-05 04:01:49

Jeśli czytasz JavaScript dobre części, zobaczysz, że zamiennikiem dla i++ w dla pętli jest i+ = 1 (nie i=i+1). To jest dość czyste i czytelne, i jest mniej prawdopodobne, aby przekształcić się w coś " trudne."

W jsLint nie ma opcji autoincrement ani autodecrement. Ty decydujesz, czy postępować zgodnie z radami, czy nie.

Moja osobista reguła to nie robić niczego w połączeniu z autoincrement lub autodecrement.

I ' ve learned z wieloletniego doświadczenia w C wynika, że nie dostaję przekroczeń bufora (lub indeksu tablicy poza granicami), Jeśli używam go prosto. Ale odkryłem, że dostaję przekroczenia bufora, jeśli wpadnę w "nadmiernie skomplikowaną" praktykę robienia innych rzeczy w tym samym oświadczeniu.

Więc, dla moich własnych reguł, użycie i++ jako przyrostu w dla pętli jest w porządku.

 49
Author: Nosredna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-09 17:34:56

W pętli jest to nieszkodliwe, ale w instrukcji przypisania może prowadzić do nieoczekiwanych wyników:

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

Biała Spacja między zmienną a operatorem może również prowadzić do nieoczekiwanych wyników:

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

W zamknięciu nieoczekiwane wyniki mogą być również problemem:

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

I uruchamia automatyczne wstawianie średnika po nowej linii:

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

Dezorientacja Preincrement/postincrement może powodować błędy off-by-one, które są niezwykle trudne do zdiagnozowania. Na szczęście są one również całkowicie niepotrzebne. Istnieją lepsze sposoby dodawania 1 do zmiennej.

Referencje

 29
Author: Paul Sweatte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-11 15:12:24

Rozważ następujący kod

    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++;

Ponieważ i++ jest oceniany dwukrotnie, wyjście jest (z debuggera vs2005)

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

Rozważ następujący kod:

    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;

Zauważ, że wyjście jest takie samo. Teraz możesz pomyśleć, że ++i i++ to to samo. Nie są

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

Wreszcie rozważ ten kod

    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++;

Wyjście jest teraz:

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

Więc nie są takie same, mieszanie obu skutkuje nie tak intuicyjnym zachowaniem. Myślę, że dla pętli jest ok z++, ale uważaj, gdy masz wiele symboli ++ w tej samej linii lub tej samej instrukcji

 17
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-09 17:30:01

Charakter "pre" i "post" operatorów przyrostowych i przyrostowych może być mylący dla tych, którzy nie są z nimi zaznajomieni; jest to jeden ze sposobów, w jaki mogą być trudne.

 16
Author: Paul Sonier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-09 17:05:54

Moim zdaniem, "jawne jest zawsze lepsze niż niejawne." ponieważ w pewnym momencie możesz pomylić się z tą deklaracją y+ = x++ + ++y. Dobry programista zawsze sprawia, że jego kod jest bardziej czytelny.

 16
Author: Sri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 19:28:28

Najważniejszym powodem unikania ++ lub -- jest to, że operatory zwracają wartości i powodują skutki uboczne w tym samym czasie, co utrudnia rozumowanie o kodzie.

Ze względu na efektywność wolę:

  • ++i when not using the return value (no temporary)
  • i++ when using the return value (no pipeline stall)
Jestem fanem Pana Crockforda, ale w tym przypadku muszę się nie zgodzić. ++i jest o 25% mniej tekst do analizy niż i+=1 i prawdopodobnie jaśniejsze.
 14
Author: Hans Malherbe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-15 07:21:14

Oglądałem film Douglasa Crockforda na ten temat i jego wyjaśnienie, że nie używam przyrostu i przyrostu jest to, że

  1. był używany w przeszłości w innych językach, aby przełamać granice tablic i spowodować wszelkie maniery zła i
  2. że jest bardziej mylące i niedoświadczeni Programiści JS nie wiedzą dokładnie, co robi.

Po pierwsze tablice w JavaScript są dynamicznie wielkości i tak, wybacz mi, jeśli się mylę, nie jest możliwe, aby przełamać granice tablicy i danych dostępowych, które nie powinny być dostępne przy użyciu tej metody w JavaScript.

Po drugie, czy powinniśmy unikać rzeczy, które są skomplikowane, z pewnością problemem nie jest to, że mamy tę funkcję, ale problem polega na tym, że są programiści, którzy twierdzą, że robią JavaScript, ale nie wiedzą, jak działają te operatory?? To dość proste. value++, podaj mi bieżącą wartość i po wyrażeniu dodaj ją do niego, ++value, zwiększ wartość przed podaniem to.

Wyrażenia takie jak A ++ + ++ B, są proste do wypracowania, jeśli tylko pamiętasz powyższe.

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

Przypuszczam, że musisz tylko pamiętać, kto musi przeczytać kod, jeśli masz zespół, który zna JS na wylot, to nie musisz się martwić. Jeśli nie to skomentuj, napisz inaczej itp. Rób, co musisz. Nie wydaje mi się, że przyrost i przyrost jest z natury zły lub generowanie błędów, lub tworzenie luk, może po prostu mniej czytelne w zależności od Twojego publiczność.

Btw, myślę, że Douglas Crockford i tak jest legendą, ale myślę, że wywołał dużo strachu przez operatora, który na to nie zasłużył. Żyję, by udowodnić, że się mylę...
 13
Author: Stuart Wakefield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-23 23:23:10

Inny przykład, prostszy od innych z prostym zwrotem wartości przyrostowej:

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

Jak widzisz, nie powinno się używać post-increment/decrement w instrukcji return, jeśli chcesz, aby ten operator miał wpływ na wynik. Ale return nie "łapie" operatorów Post-increment/decrement:

function closureIncrementTest() {
    var x = 0;

    function postIncrementX() {
        return x++;
    }

    var y = postIncrementX();

    console.log(x); // 1
}
 10
Author: Evgeny Levin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-07 04:18:05

Myślę, że programiści powinni być kompetentni w języku, którego używają; używać go jasno; i używać go dobrze. I don ' t think they should sztucznie sparaliżować język, którego używają. Mówię z doświadczenia. Kiedyś pracowałem dosłownie obok sklepu Cobol, gdzie nie używali innych "bo to było zbyt skomplikowane". Reductio ad absurdam.

 8
Author: user207421,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-27 13:27:59

Z mojego doświadczenia wynika, że ++i lub i++ nigdy nie powodowały zamieszania innego niż pierwsze poznanie, jak działa operator. Jest to niezbędne dla najbardziej podstawowych pętli for I while pętli, które są nauczane przez dowolny kurs licealny lub college nauczany w językach, w których można korzystać z operatora. Osobiście uważam, że robienie czegoś takiego jak to, co jest poniżej, aby wyglądać i czytać lepiej niż coś z++ na osobnej linii.

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

W końcu jest to preferencja stylu, a nie co więcej, ważniejsze jest to, że gdy robisz to w swoim kodzie, pozostajesz spójny, aby inni pracujący nad tym samym kodem mogli śledzić i nie musieli przetwarzać tej samej funkcjonalności na różne sposoby.

Crockford używa również i - =1, co wydaje mi się trudniejsze do odczytania niż --i lub i --
 3
Author: burdz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 17:41:20

Jak wspomniano w niektórych istniejących odpowiedziach (które irytująco nie jestem w stanie skomentować), problem polega na tym, że x++ ++X ocenia do różnych wartości (przed vs po przyroście), co nie jest oczywiste i może być bardzo mylące- Jeśli Ta wartość jest używana. cdmckay sugeruje dość mądrze, aby zezwolić na użycie operatora increment, ale tylko w taki sposób, że zwracana wartość nie jest używana, np. w jego własnej linii. Dodałbym również standardowe użycie w pętli for (ale tylko w trzecim instrukcja, której wartość zwracana nie jest użyta). Nie mogę wymyślić innego przykładu. Po "spalony" siebie, polecam te same wytyczne dla innych języków, jak również.

Nie zgadzam się z twierdzeniem, że ta nadmierna surowość wynika z niedoświadczenia wielu programistów JS. Jest to dokładnie ten rodzaj pisania typowy dla" zbyt sprytnych " programistów i jestem pewien, że jest to o wiele bardziej powszechne w bardziej tradycyjnych językach i u programistów JS, którzy mają doświadczenie w takich językach.

 2
Author: Near Privman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-27 06:53:51

Moje 2cents jest to, że należy ich unikać w dwóch przypadkach:

1) gdy masz zmienną, która jest używana w wielu wierszach i zwiększasz/zmniejszasz ją na pierwszym poleceniu, które jej używa (lub ostatnim, lub, co gorsza, w środku):

// 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 ) ...

W przykładach takich jak ten, można łatwo pominąć, że zmienna jest automatycznie zwiększana/zmniejszana lub nawet usunąć pierwszą instrukcję. Innymi słowy, używaj go tylko w bardzo krótkich blokach lub tam, gdzie zmienna pojawia się w bloku na zaledwie kilku bliskich Oświadczenia.

2) w przypadku wielokrotności ++ i -- o tej samej zmiennej w tym samym poleceniu. Bardzo trudno sobie przypomnieć, co się dzieje w takich przypadkach:

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

Egzaminy i testy zawodowe pytają o przykłady jak powyżej i rzeczywiście natknąłem się na to pytanie, szukając dokumentacji na temat jednego z nich, ale w prawdziwym życiu nie należy zmuszać do myślenia tyle o jednej linijce kodu.

 2
Author: zakmck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 10:40:02

Czy Fortran jest językiem podobnym do C? Nie ma ani++, ani --. Oto jak piszesz pętlę :

     integer i, n, sum

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

Element indeksu i jest zwiększany przez reguły języka za każdym razem przez pętlę. Jeśli chcesz zwiększyć o coś innego niż 1, Policz do tyłu przez dwa na przykład, składnia jest ...

      integer i

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

Czy Python C-jak? Używa range i list comprehensions i innych składni, aby ominąć potrzebę zwiększania indeks:

print range(10,1,-2) # prints [10,8.6.4.2]
[x*x for x in range(1,10)] # returns [1,4,9,16 ... ]
Bazując więc na tej prymitywnej eksploracji dokładnie dwóch alternatyw, projektanci języków mogą unikać ++ i -- przewidując przypadki użycia i dostarczając alternatywną składnię. Czy Fortran i Python są znacznie mniej magnesem na błędy niż języki proceduralne, które mają ++ i --? Nie mam dowodów.

Twierdzę, że Fortran i Python są podobne do C, ponieważ nigdy nie spotkałem kogoś biegłego w C, kto nie mógłby z 90% dokładnością poprawnie odgadnąć intencji nie-zaciemniony Fortran lub Python.

 1
Author: Thomas L Holaday,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-09 17:35:55