jslint工具的一个提示是:

++和—— ++(递增)和——(递减) 众所周知,操作符会导致糟糕的代码 鼓励过度狡诈。他们 仅次于有缺陷的架构 使病毒和其他 安全威胁。这是一个加分项 选项,禁止使用这些 操作符。

我知道PHP结构像$foo[$bar++]可能很容易导致off-by-one错误,但我想不出一个更好的方法来控制循环比:

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

or

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

jslint突出显示它们是因为有一些类似的语言缺少“++”和“——”语法或处理方式不同,还是有其他避免“++”和“——”的理由,我可能忽略了?


当前回答

在作为前缀和后缀使用时,操作符的含义不同,这可能会导致难以发现的错误。考虑下面的例子,使用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]);

让我们想象一下,在运行程序的过程中,我们将一个包含两项的值传递给排序函数。代码按原样运行很好:“do/while”循环在达到条件之前首先执行。然而,程序认为结束是假的,并在变量递减之前退出循环。

现在考虑下面的代码,其中——符号用作前缀,而不是后缀。这段代码将进入一个无限循环:

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

现在,当我们达到while条件时,我们在检查它之前递减结束值。返回-1,这在Javascript中是一个真值。

我对它们的使用方式没有强烈的意见,但我只是想说明,如果不小心使用它们,它们会导致真正的错误。

其他回答

C语言中有这样的历史:

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

复制一个字符串,也许这就是他所提到的过度欺骗的来源。

总是会有一个问题

++i = i++;

or

i = i++ + ++i;

实际上做的。它在一些语言中有定义,而在其他语言中并不能保证会发生什么。

撇开这些例子不谈,我认为没有什么比使用++进行递增的for循环更习惯的了。在某些情况下,您可以使用foreach循环或while循环来检查不同的条件。但是为了避免使用递增而扭曲代码是荒谬的。

考虑以下代码

    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++被求值两次,因此输出为 (from 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循环适用于++,但当你在同一行或同一指令上有多个++符号时要小心

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 ... ]

因此,基于对这两种替代方案的初步探索,语言设计人员可以通过预测用例并提供替代语法来避免++和——。

相比拥有++和——的过程式语言,Fortran和Python是否更少吸引bug ?我没有证据。

我之所以说Fortran和Python是类似C语言的语言,是因为我从来没有遇到过一个精通C语言的人不能以90%的准确率正确地猜出非混淆的Fortran或Python的意图。

我认为程序员应该精通他们所使用的语言;清楚地使用它;好好利用它。我认为他们不应该人为地削弱他们正在使用的语言。这是我的经验之谈。我曾经在一家Cobol商店的隔壁工作,他们不使用ELSE“因为它太复杂了”。荒谬还原。

根据我的经验,除了第一次学习操作符如何工作外,++i或i++从未引起过混乱。它对于最基本的for循环和while循环是必不可少的,任何高中或大学课程都是用可以使用运算符的语言教授的。我个人认为,做下面这样的事情比把++放在单独的一行上更好看。

While (a < 10){ 数组[a++] = val }

最后,这只是一种风格偏好,而不是别的什么,更重要的是,当你在代码中这样做时,你可以保持一致,这样其他人就可以使用相同的代码,而不必以不同的方式处理相同的功能。

另外,Crockford似乎使用i-=1,我发现它比——i或i——更难读懂