为什么要避免在 JavaScript 中使用递增(“”)和递减(“--”)运算符?
jslint
工具的提示之一是:
++
和--
++
(递增)和--
(递减) 众所周知,操作符会导致不良代码 鼓励过度狡猾。 他们 仅次于错误的架构 使病毒和其他 安全威胁。 有一个加号 禁止使用这些选项 运算符。
我知道像 $foo[$bar++]
这样的 PHP 结构可能很容易导致差一错误,但我找不到比 a:
while( a < 10 ) do { /* foo */ a++; }
或
for (var i=0; i<10; i++) { /* foo */ }
更好的控制循环的方法jslint
突出显示它们,因为有一些类似的语言缺少“++
”和“--
”语法或以不同的方式处理它,或者是我可能缺少避免“++
”和“--
”的其他理由吗?
One of the tips for jslint
tool is:
++
and--
The++
(increment) and--
(decrement)
operators have been known to contribute to bad code by
encouraging excessive trickiness. They
are second only to faulty architecture
in enabling to viruses and other
security menaces. There is a plusplus
option that prohibits the use of these
operators.
I know that PHP constructs like $foo[$bar++]
may easily result in off-by-one errors, but I couldn't figure out a better way to control the loop than a:
while( a < 10 ) do { /* foo */ a++; }
or
for (var i=0; i<10; i++) { /* foo */ }
Is the jslint
highlighting them because there are some similar languages that lack the "++
" and "--
" syntax or handle it differently, or are there other rationales for avoiding "++
" and "--
" that I might be missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
我的观点是始终在一行中单独使用 ++ 和 -- ,例如:
而不是
除此之外的任何内容都可能会让某些程序员感到困惑,并且在我看来这是不值得的。 For 循环是一个例外,因为增量运算符的使用是惯用的,因此总是清晰的。
My view is to always use ++ and -- by themselves on a single line, as in:
instead of
Anything beyond that can be confusing to some programmers and is just not worth it in my view. For loops are an exception, as the use of the increment operator is idiomatic and thus always clear.
C 语言有这样的历史:
复制字符串,也许这就是他所指的过度欺骗的根源。
总是存在“做什么”
或
“实际做什么”的问题。 它是在某些语言中定义的,而在其他语言中则不能保证会发生什么。
除了这些例子之外,我认为没有什么比使用
++
递增的 for 循环更惯用的了。 在某些情况下,您可以使用 foreach 循环或检查不同条件的 while 循环。 但是扭曲代码来尝试避免使用递增是荒谬的。There is a history in C of doing things like:
to copy a string, perhaps this is the source of the excessive trickery he is referring to.
And there's always the question of what
or
actually do. It's defined in some languages, and in other's there's no guarantee what will happen.
Those examples aside, I don't think there's anything more idiomatic than a for loop that uses
++
to increment. In some cases you could get away with a foreach loop, or a while loop that checked a different condtion. But contorting your code to try and avoid using incrementing is ridiculous.如果您阅读过 JavaScript The Good Parts,您会发现 Crockford 在 for 循环中对 i++ 的替换是 i+=1(而不是 i=i+1)。 这是非常干净和可读的,并且不太可能演变成“棘手”的东西。
Crockford 在 jsLint 中将禁止自动递增和自动递减作为一个选项。 您选择是否听从建议。
我个人的规则是不要做任何与自动递增或自动递减相结合的事情。
我从多年的 C 经验中了解到,如果我保持简单的使用方式,就不会出现缓冲区溢出(或数组索引越界)的情况。 但我发现,如果我陷入在同一语句中执行其他操作的“过于棘手”的做法,我确实会遇到缓冲区溢出。
因此,对于我自己的规则,使用 i++ 作为 for 循环中的增量是可以的。
If you read JavaScript The Good Parts, you'll see that Crockford's replacement for i++ in a for loop is i+=1 (not i=i+1). That's pretty clean and readable, and is less likely to morph into something "tricky."
Crockford made disallowing autoincrement and autodecrement an option in jsLint. You choose whether to follow the advice or not.
My own personal rule is to not do anything combined with autoincrement or autodecrement.
I've learned from years of experience in C that I don't get buffer overruns (or array index out of bounds) if I keep use of it simple. But I've discovered that I do get buffer overruns if I fall into the "excessively tricky" practice of doing other things in the same statement.
So, for my own rules, the use of i++ as the increment in a for loop is fine.
在循环中它是无害的,但在赋值语句中它可能会导致意外结果:
变量和运算符之间的空格也可能导致意外结果:
在闭包中,意外结果也可能是一个问题:
并且它会触发自动换行符后插入分号:
参考
In a loop it's harmless, but in an assignment statement it can lead to unexpected results:
Whitespace between the variable and the operator can lead to unexpected results as well:
In a closure, unexpected results can be an issue as well:
And it triggers automatic semicolon insertion after a newline:
References
递增和递减运算符的“前”和“后”性质对于那些不熟悉它们的人来说往往会令人困惑; 这是他们可能会变得棘手的一种方式。
The "pre" and "post" nature of increment and decrement operators can tend to be confusing for those who are not familiar with them; that's one way in which they can be tricky.
考虑以下代码,
因为 i++ 被评估两次,输出为
(来自 vs2005 调试器)
现在考虑以下代码:
请注意,输出是相同的。 现在您可能认为 ++i 和 i++ 是相同的。 它们不是
最后考虑这段代码
现在的输出是:
所以它们不一样,混合两者会导致不那么直观的行为。 我认为 for 循环对于 ++ 来说是可以的,但是当同一行或同一条指令上有多个 ++ 符号时要小心
Consider the following code
since i++ gets evaluated twice the output is
(from vs2005 debugger)
Now consider the following code :
Notice that the output is the same. Now you might think that ++i and i++ are the same. They are not
Finally consider this code
The output is now :
So they are not the same, mixing both result in not so intuitive behavior. I think that for loops are ok with ++, but watch out when you have multiple ++ symbols on the same line or same instruction
在我看来,“显式总是比隐式好。”因为在某些时候,您可能会对这个增量语句
y+ = x++ + ++y
感到困惑。 优秀的程序员总是让他或她的代码更具可读性。In my view, "Explicit is always better than implicit." Because at some point, you may got confused with this increments statement
y+ = x++ + ++y
. A good programmer always makes his or her code more readable.我一直在观看 Douglas Crockford 的视频,他对不使用增量和减量的解释是,
首先,JavaScript 中的数组是动态调整大小的,因此,如果我错了,请原谅我,不可能打破数组的边界并访问不应在 JavaScript 中使用此方法访问的数据。
其次,我们是否应该避免复杂的事情,当然问题不在于我们有这个设施,而是问题在于有些开发人员声称可以使用 JavaScript,但不知道这些运算符是如何工作的? 这很简单。 value++,给我当前值,并在表达式后加一,++value,在给我之前增加值。
如果您记住上面的内容,像 a ++ + ++ b 这样的表达式很容易计算出来。
我想你只需要记住谁必须通读代码,如果你有一个对 JS 了如指掌的团队,那么你就不需要担心。 如果没有,那么评论它,以不同的方式写它,等等。做你必须做的事情。 我不认为增量和减量本质上是不好的,或者会产生错误,或者产生漏洞,可能只是可读性较差,具体取决于您的受众。
顺便说一句,我认为道格拉斯·克罗克福德无论如何都是一个传奇人物,但我认为他对一个不值得的操作员造成了很大的恐慌。
但我活着就是为了被证明是错的……
I've been watching Douglas Crockford's video on this and his explanation for not using increment and decrement is that
Firstly arrays in JavaScript are dynamically sized and so, forgive me if I'm wrong, it is not possible to break the bounds of an array and access data that shouldn't be accessed using this method in JavaScript.
Secondly, should we avoid things that are complicated, surely the problem is not that we have this facility but the problem is that there are developers out there that claim to do JavaScript but don't know how these operators work?? It is simple enough. value++, give me the current value and after the expression add one to it, ++value, increment the value before giving me it.
Expressions like a ++ + ++ b, are simple to work out if you just remember the above.
I suppose you've just got to remember who has to read through the code, if you have a team that knows JS inside out then you don't need to worry. If not then comment it, write it differently, etc. Do what you got to do. I don't think increment and decrement is inherently bad or bug generating, or vulnerability creating, maybe just less readable depending on your audience.
Btw, I think Douglas Crockford is a legend anyway, but I think he's caused a lot of scare over an operator that didn't deserve it.
I live to be proven wrong though...
避免使用 ++ 或 -- 的最重要的理由是,运算符返回值的同时会产生副作用,从而使代码的推理变得更加困难。
为了效率起见,我更喜欢:
我是 Crockford 先生的粉丝,但在这种情况下我不得不不同意。
++i
比i+=1
需要解析的文本少了 25% 而且 可以说更清晰。The most important rationale for avoiding ++ or -- is that the operators return values and cause side effects at the same time, making it harder to reason about the code.
For efficiency's sake, I prefer:
I am a fan of Mr. Crockford, but in this case I have to disagree.
++i
is 25% less text to parse thani+=1
and arguably clearer.另一个例子,比其他一些简单返回递增值更简单:
如您所见,如果您希望此运算符影响结果,则不应在 return 语句中使用后递增/递减。 但 return 不会“捕获”后递增/递减运算符:
Another example, more simple than some others with simple return of incremented value:
As you can see, no post-increment/decrement should be used at return statement, if you want this operator to influence the result. But return doesn't "catch" post-increment/decrement operators:
我认为程序员应该胜任他们所使用的语言; 清楚地使用它; 并好好利用它。 我认为他们不应该人为地削弱他们正在使用的语言。 我是根据经验说话的。 我曾经在 Cobol 商店的隔壁工作过,那里他们不使用 ELSE,“因为它太复杂了”。 反证法。
I think programmers should be competent in the language they are using; use it clearly; and use it well. I don't think they should artificially cripple the language they are using. I speak from experience. I once worked literally next door to a Cobol shop where they didn't use ELSE 'because it was too complicated'. Reductio ad absurdam.
根据我的经验,除了第一次了解运算符如何工作时之外,++i 或 i++ 从未引起混乱。 对于以可以使用该运算符的语言教授的任何高中或大学课程所教授的最基本的 for 循环和 while 循环来说,它都是必不可少的。 我个人发现,像下面这样的操作比将 a++ 放在单独的行上看起来和阅读起来更好。
最后,这是一种风格偏好,仅此而已,更重要的是,当您在代码中执行此操作时,您会保持一致,以便其他处理相同代码的人可以遵循,而不必以不同的方式处理相同的功能。
另外,Crockford 似乎使用 i-=1,我发现它比 --i 或 i-- 更难阅读
In my experience, ++i or i++ has never caused confusion other than when first learning about how the operator works. It is essential for the most basic for loops and while loops that are taught by any highschool or college course taught in languages where you can use the operator. I personally find doing something like what is below to look and read better than something with a++ being on a separate line.
In the end it is a style preference and not anything more, what is more important is that when you do this in your code you stay consistent so that others working on the same code can follow and not have to process the same functionality in different ways.
Also, Crockford seems to use i-=1, which I find to be harder to read than --i or i--
正如一些现有答案中提到的(令人烦恼的是我无法评论),问题是 x++ ++x 评估为不同的值(增量之前和之后),这并不明显并且可能非常令人困惑 - 如果使用该值。 cdmckay 非常明智地建议允许使用增量运算符,但只能以不使用返回值的方式,例如在其自己的行上。 我还将在 for 循环中包含标准用法(但仅在第三个语句中,不使用其返回值)。 我想不出另一个例子。 我自己也被“烧伤”了,我也会为其他语言推荐同样的指南。
我不同意这种过于严格是因为很多 JS 程序员缺乏经验的说法。 这正是“过于聪明”的程序员所特有的写作方式,而且我确信这种写法在更传统的语言以及具有此类语言背景的 JS 开发人员中更为常见。
As mentioned in some of the existing answers (which annoyingly I'm unable to comment on), the problem is that x++ ++x evaluate to different values (before vs after the increment), which is not obvious and can be very confusing - if that value is used. cdmckay suggests quite wisely to allow use of increment operator, but only in a way that the returned value is not used, e.g. on its own line. I would also include the standard use within a for loop (but only in the third statement, whose return value is not used). I can't think of another example. Having been "burnt" myself, I would recommend the same guideline for other languages as well.
I disagree with the claim that this over-strictness is due to a lot of JS programmers being inexperienced. This is the exact kind of writing typical of "overly-clever" programmers, and I'm sure it's much more common in more traditional languages and with JS developers who have a background in such languages.
我的2美分是,在两种情况下应该避免它们:
1)当你有一个在许多行中使用的变量并且你在使用它的第一个语句(或最后一个,或者更糟糕的是,在中间)上增加/减少它时):
在这样的示例中,您很容易错过变量是自动递增/递减的,甚至删除第一条语句。 换句话说,仅在非常短的块中或变量仅在几个关闭语句中出现在块中的情况下使用它。
2) 如果同一语句中的同一变量有多个 ++ 和 -- 。 很难记住在这样的情况下会发生什么:
考试和专业测试询问上面的例子,事实上,我在寻找其中一个文档时偶然发现了这个问题,但在现实生活中,不应该强迫人们这样做对一行代码想了很多。
My 2cents is that they should be avoided in two cases:
1) When you have a variable that is used in many rows and you increase/decrease it on the first statement that uses it (or last, or, even worse, in the middle):
In examples like this, you can easily miss that the variable is auto-incremented/decremented or even remove the first statement. In other words, use it only in very short blocks or where the variable appears in the block on just a couple of close statements.
2) In case of multiple ++ and -- about the same variable in the same statement. It's very hard to remember what happens in cases like this:
Exams and professional tests asks about examples like above and indeed I've stumbled upon this question while looking for documentation about one of them, but in real life one shouldn't be forced to think so much about a single line of code.
Fortran 是类 C 语言吗? 它既没有 ++ 也没有 --。 这是如何编写循环:
每次循环时索引元素i都会按语言规则递增。 如果你想增加 1 以外的数字,例如倒数 2,语法是……
Python 与 C 类似吗? 它使用范围和列表推导式以及其他语法来绕过递增索引的需要:
因此,基于对两种替代方案的初步探索,语言设计者可以避免 ++ 和——通过预测用例并提供替代语法。
Fortran 和 Python 是否比具有 ++ 和 -- 的过程语言更不容易引起 bug ? 我没有证据。
我声称 Fortran 和 Python 与 C 类似,因为我从未见过精通 C 的人不能以 90% 的准确度正确猜测非混淆的 Fortran 或 Python 的意图。
Is Fortran a C-like language? It has neither ++ nor --. Here is how you write a loop:
The index element i is incremented by the language rules each time through the loop. If you want to increment by something other than 1, count backwards by two for instance, the syntax is ...
Is Python C-like? It uses range and list comprehensions and other syntaxes to bypass the need for incrementing an index:
So based on this rudimentary exploration of exactly two alternatives, language designers may avoid ++ and -- by anticipating use cases and providing an alternate syntax.
Are Fortran and Python notably less of a bug magnet than procedural languages which have ++ and --? I have no evidence.
I claim that Fortran and Python are C-like because I have never met someone fluent in C who could not with 90% accuracy guess correctly the intent of non-obfuscated Fortran or Python.
当用作前缀和后缀时,运算符的含义不同,这可能会导致难以发现的错误。 考虑以下使用 bubbleSort 的示例:
假设在运行程序的过程中,我们将两个项目的值传递到排序函数中。 代码按原样运行良好:“do/while”循环在达到条件之前首先执行。 但是,程序发现
end
为假并在递减变量之前退出循环。现在考虑以下代码,其中
--
符号用作前缀,而不是后缀。 此代码将进入无限循环:现在,当我们遇到 while 条件时,我们会在检查之前递减最终值。 这会返回 -1,在 Javascript 中是一个真值。
我对它们的使用方式没有强烈的意见,但我只是想展示它们在不小心使用时如何导致真正的错误。
The operators mean different things when used as prefixes versus suffixes, which can cause hard-to-find bugs. Consider the following example, using bubbleSort:
Let's imagine in the course of running our program, we pass a two-item value into our sort function. The code runs fine as-is: the "do/while" loop first executes before reaching the condition. However, the program sees that
end
is falsy and exits the loop before decrementing the variable.Now consider the following code, where the
--
symbol is used as a prefix, rather than a suffix. This code will enter an infinite loop:Now when we hit the while condition, we decrement the end value before checking it. This returns -1, which in Javascript, is a truthy value.
I don't have a strong opinion on their use one way or the other, but I just wanted to show how they can cause real bugs when used carelessly.
++ 的论点是 ++ 不适用于会导致 TypeError 的字符串,这几乎总是更好的选择。
Argument for ++ is that ++ is not applicable for strings which will cause TypeError, which is almost always preferable.