我们可以将if (!Array.prototype.hasOwnProperty("last")) {
Object.defineProperty(Array.prototype, "last", {
get: function() {
return this[this.length - 1];
}
});
}
console.log([9, 8, 7, 6].last); // => 6
语句写为
if
只有最后一个条件才能进入if (a == 5, b == 6, ... , thisMustBeTrue)
身体。
为什么允许?
答案 0 :(得分:67)
稍微改变你的例子,假设是这个
if ( a = f(5), b = f(6), ... , thisMustBeTrue(a, b) )
(请注意=
而不是==
)。在这种情况下,逗号保证从左到右的评估顺序。与此相反,有了这个
if ( thisMustBeTrue(f(5), f(6)) )
你不知道f(5)
之前或之后是否有人f(6)
被调用。
更正式地,逗号允许您编写表达式(a,b,c)
的序列,就像使用;
编写语句序列a; b; c;
一样。
就像;
创建sequence point(完整表达式的结尾)一样,逗号也是如此。只有序列点控制评估顺序,请参阅this post。
但当然,在这种情况下,你实际上是在写这个
a = f(5);
b = f(6);
if ( thisMustBeTrue(a, b) )
那么,逗号分隔的表达式序列何时优先于;
分隔的语句序列?我几乎不会说。当您希望右侧替换为单个表达式时,也许在宏中。
答案 1 :(得分:44)
简而言之:
尽管这样做是合法的,但在if
或while
语句的条件部分中使用逗号运算符通常没有意义(编辑:虽然后者有时可能对用户有用5534870)在他的回答中解释。)
更详细的解释:
除了它的语法功能(例如,分隔初始化列表中的元素,变量声明或函数调用/声明),在C和C ++中,,
也可以是普通的运算符,就像例如+
,所以它可以在任何地方使用,其中允许表达式(在C ++中你甚至可以重载它)。
与大多数其他运算符的不同之处在于 - 虽然双方都得到了评估 - 但它并没有以任何方式组合左右表达式的输出,而只返回正确的表达式。
之所以介绍,是因为有人(可能是Dennis Ritchie)因某种原因决定C需要一个语法来在一个位置写两个(或更多)不相关的表达式,你通常只能写一个表达式。
现在,if
语句的条件是(以及其他)这样的地方,因此,您也可以在那里使用,
运算符 - 无论这样做是否有意义是完全不同的问题!特别是 - 与...不同函数调用或变量声明 - 逗号在那里没有特殊含义,所以它确实如此:它总是这样做:它左右计算表达式,但只返回正确的结果,然后{ {1}}陈述。
我现在能想到的唯一两点,使用(非重载)if
- 运算符是有意义的:
如果要在,
循环的头部增加多个迭代器:
for
如果要在C ++ 11 constexpr函数中评估多个表达式。
再次重复此操作:在for ( ... ; ... ; ++i1, ++i2){
*i2=*i1;
}
或if
语句中使用逗号运算符 - 就像您在示例中显示的那样 - 不是明智之举。这只是另一个例子,C和C ++的语言语法允许你编写代码,这种代码的行为方式不像第一眼看到的那样。还有更多......
答案 2 :(得分:15)
对于if
语句,将某些内容放入逗号表达式而不是外部是没有意义的。
对于while
语句,将逗号表达式置于条件中时,在进入循环时执行第一部分 ,或循环时执行。如果没有代码重复,就无法轻易复制。
那么do
... while
陈述怎么样?我们只需要担心循环本身,对吧?事实证明,即使在这里,也可以通过将第一部分移动到循环中来安全地替换逗号表达式。
首先,循环体中变量的析构函数将不会被运行,这可能会有所不同。另一方面,循环中的任何continue
语句都会到达逗号表达式 的第一部分,当它确实处于条件而不是循环体中时。
答案 3 :(得分:10)
没有优点:逗号运算符只是一个表达式,其表达式列表中包含最后一个表达式的类型,而if语句计算布尔表达式。
if(<expr>) { ... }
with type of <expr> boolean
这是一个奇怪的运算符true,但它没有什么神奇之处 - 除了它在函数调用中混淆了表达式列表和参数列表。
foo(<args>)
with <args> := [<expr>[, <expr>]*]
请注意,在参数列表中,逗号与分隔参数绑定更强。
答案 4 :(得分:7)
接下来是一段时间,取决于你可能希望的那种狡猾。
考虑函数通过修改通过引用或通过指针传递的参数(可能来自设计糟糕的库,或确保在返回后未被分配而忽略此值,无论如何)来返回值的情况。
void calculateValue(FooType &result) {/*...*/}
那你如何使用依赖于result
的条件语句?
您可以声明要修改的变量,然后使用if:
进行检查FooType result;
calculateValue(result);
if (result.isBared()) {
//...
}
这可以缩短为
FooType result;
if (calculateValue(result) , result.isBared()) {
//...
}
这不值得。 但是,对于while
循环,可能会有一些小优势。如果calculateValue
应该/可以被调用,直到结果不再是bar
,我们就会有这样的结果:
FooType result;
calculateValue(result); //[1] Duplicated code, see [2]
while (result.isBared()) {
//... possibly many lines
//separating the two places where result is modified and tested
//How do you prevent someone coming after you and adds a `continue`
//here which prevents result to be updated in the and of the loop?
calculateValue(result); //[2] Duplicated code, see [1]
}
可以简化为:
FooType result;
while (calculateValue(result) , result.isBared()) {
//all your (possibly numerous) code lines go here
}
这样,更新result
的代码只在一个地方,并且位于检查其条件的行附近。
可能不相关:变量可以通过参数传递更新的另一个原因是除了修改/返回计算值之外,函数还需要返回错误代码。在这种情况下:
ErrorType fallibleCalculation(FooType &result) {/*...*/}
然后
FooType result;
ErrorType error;
while (error = fallibleCalculation(result) , (Success==error && result.isBared())) {
//...
}
但正如评论中所述,您可以在没有逗号的情况下执行此操作:
FooType result;
ErrorType error;
while (Success == fallibleCalculation(result) && result.isBared()) {
//...
}
答案 5 :(得分:4)
无论如何。该代码中a
的比较完全是多余的。
答案 6 :(得分:2)
我的问题是if
或while
声明中逗号的优势是什么?为什么允许?
它的存在是因为C语句和表达式是不同的东西。复合表达式是一种从理论(和其他一些语言)理解的构造,如果没有在表单中添加它,它将会丢失逗号。它在for
陈述中的用法是他们为什么需要它的原始理由。
但是,从理论上来说,通过使语言更加完整,它后来找到了没有人计划的用途。早期的C ++是一个生成C作为输出的翻译器,并且具有顺序表达式对于允许内联函数真正生成&#34; in line&#34;是绝对必要的。 C代码中的逻辑。
包括表达式出现的任何位置,包括 if
语句的条件。
同样,它已被用于&#34;有趣的&#34;宏。尽管C ++通过提供内联函数来消除宏,但是最新的x11编译器发现Boost FOREACH范围循环(最终,在x11中添加到语言中的功能的仿真)非常方便,那就是一个非常聪明的宏集,涉及逗号运算符。
(嗯,当前版本使用链式if
/ else
扩展为多个语句,而不是将其全部塞进一个while
。)
现在,还有另一种方法可以将任何语句放入表达式(lambdas)中,因此,模拟甚至更新语言功能或特定于域的嵌入式语言的宏的未来疯狂业务可能不会需要使用那个。
所以,不要写那样的代码。除非它比编写辅助函数或拆分成多个语句更清晰,更简单。
但是,您可能希望在一个地方轻松使用宏,而该地点位于if
或while
的内容中。在C ++源代码中托管的特定于域的语言,或者语言仿真功能(可能)是嵌入式实际中使用的异常处理的替代方法,这可能是合理的。时间系统。
简而言之,它没有正常的良好用法。但它是完整的,你永远不知道什么时候会有人发现它有用。