Waarom verhogen (“++”) en verlaag (“-“) operators in JavaScript?

een van de tips voor JSLint-tool is:

++ en –
De ++ (increment) en – (decound)
Operators zijn bekend dat ze bijdragen aan slechte code door
stimulering van buitensporige lastigheid. Zij
zijn tweede alleen voor defecte architectuur
in het inschakelen voor virussen en andere
veiligheidswedders. Er is een plusplus
optie die het gebruik hiervan verbiedt
operators.

Ik weet dat PHP-constructen zoals $foo[$bar++]gemakkelijk resulteren in off-by-one fouten, maar ik kon geen betere manier achterhalen om de lus te besturen dan een while( a < 10 ) do { /* foo */ a++; }of for (var i=0; i<10; i++) { /* foo */ }.

is de JSLINT die ze markeren, omdat er vergelijkbare talen zijn die de “++” en “--” Syntaxis anders hebben of anders, anders zijn Rationales voor het vermijden van “++” en “--” die ik misschien mis?


Antwoord 1, Autoriteit 100%

Mijn weergave is om altijd ++ en – op zichzelf te gebruiken op een enkele regel, zoals in:

i++;
array[i] = foo;

in plaats van

array[++i] = foo;

alles daarbuiten kan verwarrend zijn voor sommige programmeurs en is het gewoon niet de moeite waard in mijn mening. Voor loops is een uitzondering, omdat het gebruik van de increment-operator idiomatisch is en dus altijd duidelijk is.


Antwoord 2, Autoriteit 62%

Ik ben eerlijk gezegd in de war door dat advies. Een deel van mij wonderen als het meer te maken heeft met een gebrek aan ervaring (waargenomen of daadwerkelijk) met JavaScript-codeers.

Ik kan zien hoe iemand die gewoon een voorbeeldcode “hackt” een onschuldige fout kan maken met ++ en –, maar ik zie niet in waarom een ervaren professional ze zou vermijden.


Antwoord 3, autoriteit 16%

Er is een geschiedenis in C om dingen te doen als:

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

om een string te kopiëren, misschien is dit de bron van de buitensporige bedrog waarnaar hij verwijst.

En er is altijd de vraag wat

++i = i++;

of

i = i++ + ++i;

eigenlijk wel. Het is gedefinieerd in sommige talen, en in andere is er geen garantie wat er zal gebeuren.

Afgezien van deze voorbeelden, denk ik niet dat er iets meer idiomatisch is dan een for-lus die ++gebruikt om te verhogen. In sommige gevallen kon je wegkomen met een foreach-lus, of een while-lus die een andere voorwaarde controleerde. Maar je code verdraaien om te proberen het gebruik van ophogen te vermijden, is belachelijk.


Antwoord 4, autoriteit 12%

Als je JavaScript The Good Parts leest, zul je zien dat Crockford’s vervanging voor i++ in een forlus i+=1 is (niet i=i+1). Dat is vrij duidelijk en leesbaar, en het is minder waarschijnlijk dat het verandert in iets “lastigs”.

Crockford heeft het niet toestaan van automatisch verhogen en automatisch verlagen een optiegemaakt in jsLint. U kiest of u het advies opvolgt of niet.

Mijn eigen persoonlijke regel is om niets te doen in combinatie met automatisch verhogen of automatisch verlagen.

Ik heb uit jarenlange ervaring in C geleerd dat ik geen bufferoverschrijdingen (of array-index buiten de grenzen) krijg als ik het gebruik ervan eenvoudig houd. Maar ik heb ontdekt dat ik bufferoverschrijdingen krijg als ik in de “extreem lastige” praktijk val om andere dingen in dezelfde verklaring te doen.

Dus voor mijn eigen regels is het gebruik van i++ als increment in een for-lus prima.


Antwoord 5, autoriteit 7%

In een lus is het ongevaarlijk, maar in een toewijzingsstatement kan het tot onverwachte resultaten leiden:

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

Witruimte tussen de variabele en de operator kan ook tot onverwachte resultaten leiden:

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

Bij een afsluiting kunnen onverwachte resultaten ook een probleem zijn:

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

En het activeert automatisch het invoegen van puntkomma’s na een nieuwe regel:

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

verwarring tussen pre-increment/post-increment kan fout-voor-één fouten veroorzaken die uiterst moeilijk te diagnosticeren zijn. Gelukkig zijn ze ook compleet overbodig. Er zijn betere manieren om 1 toe te voegen aan een variabele.

referenties


Antwoord 6, Autoriteit 4%

Overweeg de volgende code

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

Sinds i ++ wordt tweemaal geëvalueerd, is de uitvoer
(van vs2005 debugger)

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

Overweeg nu de volgende code:

   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;

Merk op dat de uitvoer hetzelfde is. Nu denk je misschien dat ++ I en I ++ hetzelfde zijn. Ze zijn niet

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

Overweeg uiteindelijk deze code

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

De uitvoer is nu:

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

Dus ze zijn niet hetzelfde, het mengen van beide resultaat in niet zo intuïtief gedrag. Ik denk dat voor lussen in orde zijn met ++, maar kijk uit wanneer je meerdere ++ symbolen hebt op dezelfde lijn of dezelfde instructie


Antwoord 7, Autoriteit 4%

De aard “PRE” en “POST” van de increment en decrement-exploitanten kunnen de neiging hebben om verwarrend te zijn voor diegenen die niet bekend zijn; Dat is een manier waarop ze lastig kunnen zijn.


Antwoord 8, Autoriteit 4%

Naar mijn mening is “expliciet altijd beter dan impliciet.” Omdat je op een gegeven moment in de war bent met deze stappenverklaring y+ = x++ + ++y. Een goede programmeur maakt zijn of haar code leesbaarder altijd.


Antwoord 9, Autoriteit 4%

Ik heb de video van Douglas Crockford over het bekijken en zijn uitleg voor het niet gebruiken van verhoging en afwijzing is dat

  1. Het is in het verleden in andere talen gebruikt om de grenzen van arrays te breken en alle manieren van slechtheid en
  2. te veroorzaken

  3. dat het meer verwarrend is en onervaren JS-ontwikkelaars weten niet precies wat het doet.

Ten eerste arrays in JavaScript zijn dynamisch formaat en dus, vergeef me als ik het mis heb, het is niet mogelijk om de grenzen van een array te doorbreken en toegangsgegevens die niet toegankelijk zijn om deze methode in JavaScript te gebruiken.

In de tweede plaats moeten we dingen vermijden die gecompliceerd zijn, zeker het probleem is niet dat we deze faciliteit hebben, maar het probleem is dat er ontwikkelaars daar zijn die beweren te doen JavaScript, maar weet niet hoe deze operatoren werken? Het is eenvoudig genoeg. Waarde ++, geef me de huidige waarde en voeg na de uitdrukking er een toe, ++ waarde, verhoog de waarde voordat je me het geeft.

Uitdrukkingen zoals A ++ + ++ B, zijn eenvoudig te trainen als u het hierboven herinnert.

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

Ik veronderstel dat je je net moet herinneren wie de code door de code moet lezen, als je een team hebt dat JS Binnenbinnen kent, hoeft u zich geen zorgen te maken. Als je het dan niet opmerkt, schrijf het anders, enz. Doe wat je moet doen. Ik denk niet dat de toename en de afname inherent slecht of insect genereert, of kwetsbaarheid creëert, misschien gewoon minder leesbaar, afhankelijk van uw publiek.

BTW, ik denk dat Douglas Crockford toch een legende is, maar ik denk dat hij veel bang is voor een operator die het niet verdient.

Ik leef om te worden bewezen dat het ongelijk is …


Antwoord 10, Autoriteit 3%

De belangrijkste reden voor het vermijden van ++ of – is dat de operators waarden terugkeren en bijwerkingen tegelijkertijd veroorzaken, waardoor het moeilijker is om te redeneren over de code.

Voor de efficiëntie, ik geef de voorkeur:

  • ++ I wanneer niet gebruikt de retourwaarde (geen tijdelijke)
  • I ++ wanneer met de retourwaarde (geen pijplijnstalles)

Ik ben een fan van Mr. Crockford, maar in dit geval moet ik het oneens zijn. ++iis 25% minder tekst om te parseren dan i+=1en aantoonbaar duidelijker.


Antwoord 11, Autoriteit 2%

Nog een voorbeeld, eenvoudiger dan sommige anderen met een eenvoudige terugkeer van verhogende waarde:

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

Zoals je kunt zien, mag er geen post-increment/decrement worden gebruikt bij de return-instructie, als je wilt dat deze operator het resultaat beïnvloedt. Maar return “vangt” geen post-increment/decrement-operators:

function closureIncrementTest() {
    var x = 0;
    function postIncrementX() {
        return x++;
    }
    var y = postIncrementX();
    console.log(x); // 1
}

Antwoord 12, autoriteit 2%

Ik vind dat programmeurs bekwaam moeten zijn in de taal die ze gebruiken; gebruik het duidelijk; en gebruik het goed. Ik nietdenk dat ze de taal die ze gebruiken kunstmatig moeten verlammen. Ik spreek uit ervaring. Ik heb ooit letterlijk naast een Cobol-winkel gewerkt waar ze ELSE niet gebruikten ‘omdat het te ingewikkeld was’. Reductio ad absurdam.


Antwoord 13

In mijn ervaring heeft ++i of i++ nooit voor verwarring gezorgd, behalve toen ik voor het eerst leerde hoe de operator werkt. Het is essentieel voor de meest elementaire for-loops en while-loops die worden gegeven door een middelbare school of universiteitscursus die wordt gegeven in talen waarin u de operator kunt gebruiken. Persoonlijk vind ik zoiets als wat hieronder staat om er beter uit te zien en te lezen dan iets met a++ op een aparte regel.

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

Antwoord 14

Zoals vermeld in sommige van de bestaande antwoorden (waar ik helaas geen commentaar op kan geven), is het probleem dat x++ ++x naar verschillende waarden evalueert (vóór versus na de toename), wat niet voor de hand ligt en kan worden erg verwarrend – alsdie waarde wordt gebruikt. cdmckay stelt heel verstandig voor om het gebruik van de increment-operator toe te staan, maar alleen op een manier dat de geretourneerde waarde niet wordt gebruikt, b.v. op zijn eigen lijn. Ik zou ook het standaardgebruik in een for-lus opnemen (maar alleen in de derde instructie, waarvan de retourwaarde niet wordt gebruikt). Ik kan geen ander voorbeeld bedenken. Omdat ik zelf “verbrand” ben, zou ik dezelfde richtlijn ook voor andere talen aanbevelen.

Ik ben het niet eens met de bewering dat deze overdreven striktheid te wijten is aan het feit dat veel JS-programmeurs onervaren zijn. Dit is precies het soort schrijven dat typisch is voor “overdreven slimme” programmeurs, en ik weet zeker dat het veel vaker voorkomt in meer traditionele talen en bij JS-ontwikkelaars die een achtergrond hebben in dergelijke talen.


Antwoord 15

Mijn 2 cent is dat ze in twee gevallen moeten worden vermeden:

1) Als u een variabele heeft die in veel rijen wordt gebruikt en u verhoogt/verlaagt deze bij de eerste instructie die deze gebruikt (of als laatste, of, erger nog, in het midden):

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

In voorbeelden als deze kun je gemakkelijk over het hoofd zien dat de variabele automatisch wordt verhoogd/verlaagd of zelfs de eerste instructie wordt verwijderd. Met andere woorden, gebruik het alleen in zeer korte blokken of waar de variabele in het blok verschijnt bij slechts een paar sluitinstructies.

2) In het geval van meerdere ++ en — ongeveer dezelfde variabele in dezelfde instructie. Het is erg moeilijk om te onthouden wat er gebeurt in dit soort gevallen:

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

Examens en professionele tests vragen naar voorbeelden zoals hierboven en ik ben inderdaad op deze vraag gestuit toen ik op zoek was naar documentatie over een van hen, maar in het echte leven zou je niet zo veel moeten nadenken over een enkele regel code .


Antwoord 16

Is Fortran een C-achtige taal? Het heeft geen ++ of –. Hier is hoe je een lus schrijft:

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

Het indexelement iwordt elke keer door de lus verhoogd met de taalregels. Als u wilt verhogen met iets anders dan 1, bijvoorbeeld terugtellen met twee, is de syntaxis …

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

Is Python C-achtig? Het gebruikt bereiken lijstbegrippenen andere syntaxis om de noodzaak voor het verhogen van een index te omzeilen:

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

Dus op basis van deze rudimentaire verkenning van precies twee alternatieven, kunnen taalontwerpers ++ en — vermijden door te anticiperen op gebruiksscenario’s en een alternatieve syntaxis te bieden.

Zijn Fortran en Python opmerkelijk minder een bugmagneet dan proceduretalen die ++ en — hebben? Ik heb geen bewijs.

Ik beweer dat Fortran en Python C-achtig zijn, omdat ik nog nooit iemand heb ontmoet die vloeiend is in C en die niet met 90% nauwkeurigheid de bedoeling van niet-verhulde Fortran of Python correct kon raden.


Antwoord 17

De operators bedoelen verschillende dingen wanneer ze worden gebruikt als voorvoegsels versus achtervoegsels, wat moeilijk te vinden bugs kan veroorzaken. Beschouw het volgende voorbeeld met bubbleSort:

function bubbleSort(array) {
  if(array.length === 1) return array;
  let end = array.length - 2;
  do {
    for (let i = 0; i < array.length; i += 1) {
      if (array[i] > array[i + 1]) {
        swap(array, i, i + 1);
      }
    }
  } while (end--);
}
bubbleSort([6,5]);

Laten we ons voorstellen dat we tijdens het uitvoeren van ons programma een waarde van twee items doorgeven aan onze sorteerfunctie. De code werkt prima zoals het is: de “do/while”-lus wordt eerst uitgevoerd voordat de voorwaarde wordt bereikt. Het programma ziet echter dat endonwaar is en verlaat de lus voordat de variabele wordt verlaagd.

Beschouw nu de volgende code, waarbij het symbool --wordt gebruikt als voorvoegsel in plaats van als achtervoegsel. Deze code gaat een oneindige lus in:

function bubbleSort(array) {
  if(array.length === 1) return array;
  let end = array.length - 2;
  do {
    for (let i = 0; i < array.length; i += 1) {
      if (array[i] > array[i + 1]) {
        swap(array, i, i + 1);
      }
    }
  } while (--end);
}
bubbleSort([6,5]);

Nu, wanneer we de TERWIJLS-aandoening raken, verijden wij de eindwaarde vóór controleren. Dit retourneert -1, die in Javascript een waarheidsgraad is.

Ik heb geen sterke mening over hun gebruik een of andere manier, maar ik wilde gewoon laten zien hoe ze echte bugs kunnen veroorzaken wanneer ze achteloos worden gebruikt.

Other episodes