在JavaScript中,使用感叹号的情况下,unless和if有什么区别?

14
下面的代码试图打印出“是偶数”的数字,该怎么办?
它不应该是if(test)then(),而是if(!test)then()吗?当测试条件为“n%2”时,下面的代码似乎读取“如果数字不能被2整除,则打印出'number is even'”,这似乎不合逻辑。
更一般地说,在指定条件时编写Unless函数的优点是什么,当我们可以简单地编写if(!condition)时,使用If语句即可?
非常感谢任何帮助。
function unless(test, then) {
  if (!test) then();
}
function repeat(times, body) {
  for (var i = 0; i < times; i++) body(i);
}

repeat(5, function(n) {
  unless(n % 2, function() {
    console.log(n, "is even");
});
// → 0 is even
// → 2 is even
// → 4 is even

% 不是用来测试可除性的,它是一个模运算操作符。这段代码测试 n % 2 是否计算出可以被视为假(即 0),如果是,则表示 n 是偶数。 - anon
下面的代码尝试打印出可以被2整除的数字的“是偶数”。它不是“尝试”,而是确实这样做了。(至少,一旦您在结尾处修复语法错误,它就会这样做。)无论如何,我同意“除非”的想法在语义上对于此测试并不真正有意义,但是该代码确实具有所需的输出。这些类型的函数看起来属于测试框架,让您进行断言并在断言证明为假时执行某些操作。 - nnnnnn
2
这段代码很糟糕,正如没有仔细分析就无法清楚地知道它的作用一样。这里没有任何优势。在一般情况下,我无法说明其优势。也许在你的“尖头老板”说必须这样做,否则就会被解雇时,这种方式是有优势的。你需要给出可能需要使用这种方式的上下文,才能使这个问题可行。 - djechlin
@djechlin 这段代码是Eloquent JavaScript的一部分。它在这里似乎脱离了上下文,只是用来解释高阶函数的一个例子。 - Mahdi
1
代码是正确的。你对整数除法的理解是错误的。它不是“如果数字不能被2整除”,而是“如果一个数除以2没有余数”。 - slebetman
3个回答

7
这样做的争议性优点在于代码读起来更像英语:“除非n模2不为零,否则记录到控制台n是偶数。”
根据我的经验,这样做的实际后果是大多数程序员会在感觉舒适之前必须仔细检查unless()函数的作用。因为它不是Javascript的标准部分,他们无法知道它是否使用!或==true或===0或其他略有不同的测试,除非他们去查看实现。
我最喜欢的例子是COBOL。该语言试图非常像英语,以便即使非程序员也可以使用它...但实际上,程序员和非程序员似乎都讨厌使用它。

1
在这个语境中,我基本上同意你写的一切。然而,当以以下方式使用Perl时,它可以非常优雅地完成任务:go_outside() and play() unless $is_raining;。在这个具体的例子中,使用它没有任何惩罚,但是像Perl中的所有东西一样,它很容易被滥用,从而使代码变得可读。 - Eirik Birkeland

2

如果条件直接内联提供,那么就没有任何优势。您可以轻松地应用转换以在所有情况下否定它(例如,在前面添加!),并且将unless排除在外意味着读者需要了解的内容更少。

如果条件是以回调函数的形式提供的,则可能会有一些优势,例如:

function test() { return true; }
function unless(test, then) { if (!test()) then(); }

unless(test, function() { console.log("test failed"); });

在这种情况下,你不能直接将 test 的否定传递给与 unless 互补的假设函数 onlyIf,因此同时拥有 onlyIfunless 可以使代码更易读,因为它允许你这样做:
onlyIf(test, function() { console.log("test passed"); });

用这个代替:

onlyIf(function() { return !test(); }, function() { console.log("test passed"); });

上述情况如果回调函数需要传递到test中,则情况可能会更糟。

0

我同意 Mahdi 的观点,认为这可能是对回调函数一个故意奇怪的例子做出的反应,但为了完整性——加上对否定的特别兴趣——还有一种选择:

if(test){}else{then}

即使在箭头函数出现后,这种方法比unless()更短。它保持了“在表达式上获得免费通行证”的隐喻。我认为,为了语法上的原因进一步争论!或?:运算符是不现实的,实际上需要语言允许:

else(test){then}

鉴于此,我仍然会选择前者,因为它更具灵活性和现有性。:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接