【问题标题】:Purpose of redundant conditions in if-then clause with && (and) operator?带有&&(and)运算符的if-then子句中冗余条件的目的?
【发布时间】:2015-05-08 19:53:00
【问题描述】:

我不理解下面的 if-then-else 子句,这是我在我正在处理的一段代码中发现的。

if (prefstocking && prefstocking >0) {
    ...
} else {
    ...
}

为什么变量prefstocking出现在逻辑运算符&&的两边?我认为使用逻辑运算符&& 意味着同时使用它们,就像这样:if (x && y = 1) 对我来说很有意义,意思是“如果 x 等于 1 并且 y 等于 1”,但是两次使用相同的值是什么意思?

【问题讨论】:

  • prefstocking && prefstocking > 0 表示(prefstocking) && (prefstocking > 0)。因此,它正在检查以确保 prefstocking 不是虚假的,并且它大于 0。似乎是合理的
  • @wolffer-east 但([false|0|undefined|null|''] > 0) 为假;为什么还要费心检查虚假性呢?
  • @Mathletics 因为我从未实际测试过([false|0|undefined|null|''] > 0)。现在它似乎根本不合理:)。条件的逻辑分离仍然需要注意,尽管两者兼有的有效性
  • @wolffer-east 这就是我的观点;人们用这些东西来修饰他们的代码,因为他们没有逻辑地思考正在发生的事情。
  • 这里的其他人似乎忽略了这样一个事实,即如果第一个测试失败,那么解释器甚至不需要检查第二个条件——而且可能不会。尽管额外的条件在数学上可能是多余的,但由于计算顺序的原因,首先包含冗余的简单检查以提高效率可能仍然很有价值。

标签: javascript if-statement operators logical-operators


【解决方案1】:

这个测试用简单的英语书写,内容如下:

如果 prefstocking 是真的并且它的值大于 0

然而,由于大多数值是真实的,前一个检查是不必要的。任何不符合第一个条件的情况也将不符合第二个条件。我看到许多开发人员编写此类检查是为了额外确定,但这告诉我他们根本没有考虑自己在做什么。

【讨论】:

  • 它检查的不仅仅是变量是否存在(已定义),如""null0“存在”。看起来他们更像是在检查值是否为0,然后继续检查它是否为非负数(尽管这是推测)。
  • @RobM。但是在一个表达式中,有什么意义呢?如果条件是嵌套的,那可能是合理的。但在一个表达式中,a > 0 会告诉您 a && a > 0 会告诉您的所有内容。
  • 我完全同意,在这种特殊情况下这是毫无意义的检查;我只是指出,条件检查的不仅仅是变量是否已定义。
  • @RudePeopleStepOff 这很容易进行基准测试,但听起来像是一个荒谬的微优化。
  • 与此实例中优化的 size 无关。难道我们不是在试图写出不仅对这个特定的人在他非常具体的情况下有帮助的答案吗?在具有相同基本结构的不同环境中,优势可能是巨大的。
【解决方案2】:

第一部分 if (prefstocking && ...) 检查 var prefstocking 中的 falsenullundefined、0、NaN 和空字符串。 这些都称为"falsy" 值。

如果 prefstocking 是“假的”,那么它不大于零并且不需要检查。

Another answer 详细介绍了 JavaScript 中的truthy v. falsy。

在这种情况下,如果测试是 if (prefstocking > 0) 则没有区别,因为它的计算结果总是与原始结果相同,但主体通常很有用,尤其是在避免取消引用 null 或未定义对象时。

var obj1 = someFunction('stuff', 9); // assume it returns an object
var obj2 = getNullObj(); // assume it always returns null

// this is OK if an object is always returned from the someFunction(...) call
if (obj1.hasData()) { }
// this causes an error when trying to call the .hasData() method on a null or undefined object
if (obj2.hasData()) { }

但是,因为逻辑 and &&or || 运算符 short-circuit,这样的测试是安全的:

if (obj2 && obj2.hasData()) { }

如果第一部分为假(假),它不会尝试评估第二部分,因为逻辑真理已经知道 - 如果 and 的第一部分是,则整个陈述是错误的错误的。这意味着如果 obj2 为 null 或未定义,则永远不会调用 .hasData()

如果一个对象定义但没有.hasData()函数,那么这将仍然导致错误。防御可能看起来像

if (obj2 && obj2.hasData && obj2.hasData()) { }
// ...or...
if (obj2 && typeof obj2.hasData === 'function' && obj2.hasData()) { }

短路允许您检查和避免故障情况,但检查每个可能的故障可能会使您的代码不可读并且性能不佳;用你的判断力。

【讨论】:

    【解决方案3】:

    其他人指出阅读本文的方式是(prefstocking) && (prefstocking > 0) 是正确的。第一个条件检查预存货是否真实。第二个条件确保它大于 0。现在,为什么要这样做呢?在这里我不同意其他答案。

    在编程中,出于效率考虑,我们可能会在 if then 子句中使用冗余条件。在这种情况下,从数学上讲,第一个条件是多余的。也就是说,如果第二个条件为真,那么第一个条件也为真。但是,顺序很重要。如果解释器检查第一个条件并发现它为假,然后是 && (and),则不需要进一步测试。而且它可能不会测试第二个条件(参见下面的 cmets:根据 ECMAScript 标准,它肯定不会测试第二个条件)。如果检查第一个条件的计算成本较低,例如首先排除空情况,这可能很有用。 是否实际上更高效的细节很难用 JavaScript 量化,因为内部通常没有指定,每个 JS 解释器都以自己的方式工作。

    此外,if (x && y == 1) 形式的表达式将被解释为“如果 x 为真且 y 等于 1”。你误解了操作的顺序。 && 的两边分别制定条件。它们不会像英语中的可能那样组合成一个条件。这个表达式当然并不意味着“如果 x 和 y 等于 1”。确保你已经理解了。

    【讨论】:

    • "它可能不会测试第二个条件" — 如果第一个条件为假,保证不测试第二个条件,因为&&|| 都使用 short-circuit 评估规则。
    • @StephenP 好。那么我说的是真的。但是你怎么知道 JavaScript 解释器实际上在内部做什么呢?
    • ECMAScript 规范定义了执行此操作的语言,因此任何符合要求的解释器都会执行此操作。您可以通过创建一个执行诸如if ( callFalse() and callTrue() ) { console.log("test #1 failed"); } else { console.log("test #1 passed"); } 之类的功能的套件来测试任何给定的 JavaScript 引擎——并且还可以将 callTrue() 和 callFalse() 写入控制台以显示它们被(或未被)调用。
    • @StephenP 好。我真诚地感谢您添加更多信息。我希望你不会反对我说我使用了保守的语言。既然您已经发表了评论,未来的读者将会有一个更完整的理解。我投票支持你的 cmets。
    • @StephenP 的回答非常好,并提供了我在这里提到的一些主题的更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多