代码之家  ›  专栏  ›  技术社区  ›  artlung

为什么要在JavaScript中避免递增(“+”)和递减(“--”)运算符?

  •  337
  • artlung  · 技术社区  · 15 年前

    其中一个 tips for jslint tool

    ++及--
    ++(递增)和--(递减) 鼓励过度的欺骗。他们 在启用病毒和其他 禁止使用这些工具的选项 接线员。

    我知道PHP结构像 $foo[$bar++] while( a < 10 ) do { /* foo */ a++; } for (var i=0; i<10; i++) { /* foo */ } .

    jslint之所以突出显示它们,是因为有一些类似的语言缺少“ ++ -- “语法或以不同的方式处理,或者有其他理由可以避免” ++ --

    17 回复  |  直到 3 年前
        1
  •  427
  •   Rohit Sharma    5 年前

    我的观点是始终在一行上使用++和-,如:

    i++;
    array[i] = foo;
    

    而不是

    array[++i] = foo;
    

        2
  •  262
  •   Vikrant Mayank    6 年前

    坦率地说,我被那个建议弄糊涂了。我有一部分想知道这是否与javascript程序员缺乏经验(感知的或实际的)有关。

    我可以理解,如果有人只是“黑客”编写一些示例代码,那么他可能会在++和--上犯一个无辜的错误,但我不明白为什么有经验的专业人员会避免这些错误。

        3
  •  70
  •   Salman A    11 年前

    在C语言中,有这样做的历史:

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

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

    ++i = i++;
    

    i = i++ + ++i;
    

    实际上是这样。它是用一些语言定义的,而在另一些语言中,无法保证会发生什么。

    撇开这些例子不谈,我认为没有什么比使用 ++

        4
  •  49
  •   Nosredna    15 年前

    如果你阅读JavaScript的好部分,你会看到Crockford在一个新的版本中取代了i++

    Crockford将禁止自动递增和自动递减设置为 选项 在jsLint中。你可以选择是否听从建议。

    因此,对于我自己的规则,使用i++作为 对于 循环是好的。

        5
  •  30
  •   Paul Sweatte    5 年前

    在循环中它是无害的,但在赋值语句中它可能导致意外的结果:

    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添加到变量中。

    工具书类

        6
  •  17
  •   Eric    15 年前

    考虑下面的代码

        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++得到两次求值,因此输出为 (来自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++是一样的。它们不是

    [1] 0整数
    [2] 2整数
    [3] 0整数
    [4] 4整数
    

    最后考虑这个代码

        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
    

        7
  •  16
  •   Paul Sonier    15 年前

    增量和减量运算符的“前”和“后”性质可能会让不熟悉它们的人感到困惑;这是他们可能很狡猾的一种方式。

        8
  •  16
  •   artlung    13 年前

    在我看来,, 因为在某个时候,你可能会被这句话弄糊涂 y+ = x++ + ++y

        9
  •  15
  •   Tony    12 年前

    我一直在看Douglas Crockford关于这个的视频,他对不使用递增和递减的解释是

    1. 过去,在其他语言中,它被用来打破数组的界限,并导致各种不良行为和错误
    2. 更令人困惑的是,缺乏经验的JS开发人员不知道它到底做什么。

    首先,JavaScript中的数组是动态调整大小的,因此,如果我错了,请原谅,在JavaScript中不可能打破数组的界限并访问不应该使用此方法访问的数据。

    第二,我们应该避免复杂的事情,问题当然不是我们有这个功能,而是有一些开发人员声称做JavaScript,但不知道这些操作符是如何工作的??这很简单。value++,给我当前值,在表达式后面加一,++value,在给我之前增加值。

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

    我想你只需要记住谁必须通读代码,如果你的团队对JS了如指掌,那么你就不必担心了。如果没有,那么评论它,用不同的方式写它,等等。做你该做的。我不认为增量和减量本质上是不好的,也不认为是产生bug或漏洞的,可能只是因为读者的不同而不那么可读。

    顺便说一句,我认为道格拉斯·克罗克福德无论如何都是一个传奇,但我认为他对一个不配的接线员造成了很大的恐慌。

    我活着就是为了被证明是错的。。。

        10
  •  14
  •   Hans Malherbe    7 年前

    避免使用++或-,最重要的理由是运算符返回值并同时产生副作用,这使得对代码进行推理变得更加困难。

    • ++我 什么时候 返回值(无临时值)
    • 我++ 什么时候

    ++i 要分析的文本比 i+=1

        11
  •  10
  •   ide    7 年前

    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语句中使用post递增/递减。但return不会“捕获”后递增/递减运算符:

    function closureIncrementTest() {
        var x = 0;
    
        function postIncrementX() {
            return x++;
        }
    
        var y = postIncrementX();
    
        console.log(x); // 1
    }
    
        12
  •  9
  •   user207421    14 年前

    我认为程序员应该能够胜任他们所使用的语言;清楚地使用它;好好利用它。我 不要 认为他们应该人为地削弱他们正在使用的语言。我凭经验说话。我曾经在一家Cobol商店的隔壁工作,“因为太复杂了”,他们没有使用其他工具。

        13
  •  3
  •   burdz    8 年前

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

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

        14
  •  2
  •   Near Privman    13 年前

    正如在一些现有答案中提到的(令人烦恼的是,我无法对其进行评论),问题在于x++++x计算为不同的值(在增量之前和之后),这并不明显,并且可能会非常混乱- 如果 使用该值。cdmckay非常明智地建议允许使用增量运算符,但仅以不使用返回值的方式,例如在其自己的行上。我还将在for循环中包含标准用法(但仅在第三条语句中,其返回值未使用)。我想不出另一个例子了。我自己也被“烧死”了,我建议其他语言也采用同样的指导原则。

        15
  •  2
  •   zakmck    8 年前

    我的理由是,在两种情况下应避免使用:

    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) 如果有多个++和-,则在同一语句中有大约相同的变量。很难记住在这种情况下会发生什么:

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

    考试和专业测试都会询问上述示例,事实上,我在寻找其中一个示例的文档时偶然发现了这个问题,但在现实生活中,不应该强迫人们对一行代码考虑太多。

        16
  •  1
  •   Thomas L Holaday    15 年前

    how you write a loop :

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

    索引元素 每次通过循环时,由语言规则递增。如果你想增加除1以外的数值,倒计时2例如,语法是。。。

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

    Python是C-like吗?它使用 范围 列表推导式

    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的意图。

        17
  •  0
  •   Harrison Cramer    3 年前

    当用作前缀和后缀时,运算符的含义不同,这可能导致难以找到的bug。考虑下面的例子,使用BuffelORT:

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

    end

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

    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中,它是一个真实值。

    我对它们的这种或那种使用方式没有强烈的意见,但我只是想展示一下它们在不小心使用时是如何引起真正的bug的。