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

2020/09/30 07:21 · javascript ·  · 0评论

jslint工具提示之一是:

++和-

众所周知,++(递增)和-(递减)运算符会通过鼓励过度的技巧而导致不良代码。
在支持病毒和其他安全威胁方面,它们仅次于错误的体系结构。有一个plusplus选项禁止使用这些运算符。

我知道像这样的PHP构造$foo[$bar++]很容易会导致一次错误的错误,但是我找不到比awhile( a < 10 ) do { /* foo */ a++; }更好的方法来控制循环for (var i=0; i<10; i++) { /* foo */ }

jslint是否将其突出显示,是因为有些相似的语言缺少“ ++”和“ --”语法或以不同的方式处理它,还是有其他理由避免我可能会丢失++”和“ --”?

我的观点是总是单独使用++和-,如下所示:

i++;
array[i] = foo;

代替

array[++i] = foo;

除此之外,其他任何事情都可能使某些程序员感到困惑,在我看来这是不值得的。For循环是一个例外,因为增量运算符的使用是惯用的,因此始终是清楚的。

坦率地说,我对这个建议感到困惑。我的一部分想知道它是否与缺乏JavaScript编码器经验(感知的或实际的)有关。

我可以看到有人只是“窃听”一些示例代码会如何用++和-犯一个无辜的错误,但是我不明白为什么有经验的专业人员会避免使用它们。

C中有做类似这样的事情的历史:

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

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

而且总是有一个问题

++i = i++;

要么

i = i++ + ++i;

确实可以。它是在某些语言中定义的,而在其他语言中则无法保证会发生什么。

除了那些示例,我认为没有什么比用于++递增的for循环更惯用的了在某些情况下,您可以放弃foreach循环或while循环来检查其他条件。但是扭曲代码以尝试避免使用增量是荒谬的。

如果您阅读JavaScript The Good Parts,您会发现Crockford在for循环中对i ++的替代是i + = 1(不是i = i + 1)。这很干净而且可读,并且不太可能变成“棘手”的东西。

Crockford在jsLint中将禁止自动递增和自动递减设为选项您选择是否遵循建议。

我个人的规则是不要将任何事情与自动递增或自动递减结合起来。

我从多年的C经验中学到,如果我继续简单地使用它,就不会缓冲区溢出(或数组索引超出范围)。但是我发现,如果我陷入了在同一条语句中做其他事情的“过分棘手”的作法,我的确会出现缓冲区溢出。

因此,按照我自己的规则,可以将i ++用作for循环的增量

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

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

参考文献

考虑以下代码

    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 ++是相同的。他们不是

    [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循环对于++来说还可以,但是当您在同一行或同一指令上有多个++符号时要当心

增量和减量运算符的“前置”和“后置”性质可能会使那些不熟悉它们的人感到困惑;这是他们变得棘手的一种方式。

在我看来,“显式总比隐式好。” 因为在某些时候,您可能会对此递增声明感到困惑y+ = x++ + ++y一个好的程序员总是使他或她的代码更具可读性。

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

为了提高效率,我更喜欢:

  • ++ i的不使用的返回值(没有临时)
  • 我++使用的返回值(无流水线失速)

我是克罗克福德先生的粉丝,但在这种情况下,我必须不同意。++i是文本解析低于25% i+=1 可以清晰的。

我一直在看道格拉斯·克罗克福德(Douglas Crockford)的视频,他对不使用增量和减量的解释是

  1. 过去,它已在其他语言中用于打破数组的界限,并导致各种不良情况。
  2. 令人困惑的是,经验不足的JS开发人员并不确切知道它的作用。

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

其次,我们应该避免复杂的事情吗?问题肯定不是我们拥有此功能,而是问题在于那里有声称声称使用JavaScript但不知道这些运算符如何工作的开发人员?很简单。value ++,给我当前值,在表达式中加上一个值,即++ value,在给我之前增加值。

如果您只记得上面的内容,则像++ + ++ b这样的表达式很容易计算出来。

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的团队,那么您就不必担心。如果没有,请对其进行注释,然后以不同的方式编写,等等。我不认为递增和递减本来就不好,也不是会产生错误,也不是会产生漏洞,根据您的听众而定,其可读性可能较低。

顺便说一句,我认为道格拉斯·克罗克福德(Douglas Crockford)仍然是一个传奇,但我认为他对一个不值得的运营商造成了很多恐慌。

虽然我被证明是错误的...

另一个示例,比其他一些示例更简单,只需简单地返回增值:

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
}

我认为程序员应该在使用的语言方面胜任。清楚地使用它;并很好地使用它。认为他们应该人为地削弱他们使用的语言。我从经验上讲。我曾经在Cobol商店的隔壁工作过,在那里他们不使用ELSE,因为那太复杂了。还原荒谬。

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

我不同意这种过度限制是由于许多JS程序员缺乏经验的说法。这是“聪明的”程序员的典型写法,而且我敢肯定,它在更传统的语言中以及具有这种语言背景的JS开发人员中更为常见。

以我的经验,++ i或i ++从来没有引起混乱,除非是第一次了解运算符的工作原理。对于最高级的for循环和while循环,这是必不可少的,而在任何高中或大学课程中,只要您可以使用运算符就可以教这些循环。我个人觉得做下面的事情要比在单独的行中用a ++做得更好。

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

最后,它是样式首选项,仅此而已,更重要的是,当您在代码中执行此操作时,您将保持一致,以便其他从事同一代码的人可以遵循它们,而不必以不同的方式处理相同的功能。

另外,克罗克福德似乎使用i- = 1,我发现它比--i或i--难读

我的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 ) ...

在这样的示例中,您很容易错过变量是自动递增/递减的,甚至删除了第一条语句。换句话说,仅在非常短的块中使用变量,或者仅在几个close语句中变量出现在块中的地方使用它。

2)如果有多个++和-关于同一条语句中的同一变量。很难记住在这种情况下会发生什么:

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

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

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是否明显不吸引人?我没有证据。

我声称Fortran和Python就像C一样,因为我从未遇到过精通C的人,他们不能以90%的准确度正确猜出没有混淆的Fortran或Python的意图。

本文地址:http://javascript.askforanswer.com/weishenmeyaobimianzaijavascriptzhongshiyongzengliang-hejianliang-yunsuanfu.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!