【问题标题】:How to avoid ternary on complicated boolean expression如何避免复杂布尔表达式的三元
【发布时间】:2016-05-16 06:09:07
【问题描述】:

在检查我的 Javascript 时,我遇到了一个关于我的复杂三元选项的 no-unneeded-ternary 警告。

我知道如何用简单的布尔表达式解决这个问题:

var obvious = (1 === 1) ? true : false;
// can simply become:
var obvious = (1 === 1);

但是,在我下面的布尔表达式中,我不知道如何正确地缩小范围,而不必担心会破坏一些恰好非常复杂的东西:

const include =
  (options.directory && file !== '.') ? false :
  (!dotted) ? true :
  (dotted && options.all) ? true :
  (dotted && !implied && options.almostall) ? true :
  (options.directory && file === '.') ? true :
  false;

什么是正确的速记实现?


试一试:

const include = !(options.directory && file !== '.') || 
  (!dotted) || 
  (dotted && options.all) ||
  (dotted && !implied && options.almostall) ||
  (options.directory && file === '.');

这对吗?

【问题讨论】:

  • 在我看来——虽然有时为复杂条件提出单行代码看起来确实令人印象深刻,但像这样的模式不可读,而且代码也不是很可继承。我同意优化等。但在这种情况下,辅助函数中的 if..else 不会对保持可读性造成伤害

标签: javascript boolean ternary-operator


【解决方案1】:

当您使用一堆链接的三元运算符编写代码时,它会变得更简洁,通常可读性更低。

const include =
  (options.directory && file !== '.') ? false :
  (!dotted) ? true :
  (dotted && options.all) ? true :
  (dotted && !implied && options.almostall) ? true :
  (options.directory && file === '.') ? true :
  false;

为了分解它,我将首先使用模块模式对其进行扩展:

include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    if (!dotted)
        return true;

    if (dotted && all)
        return true;

    if (dotted && implied && almost)
        return true;

    if (directory && isDot)
        return true;

    return false;
}());

这可以简化。检查!dotted后,dotted一定为真,成为多余:

true && a

转换为:

a
include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    if (!dotted)
        return true;

    if (all)
        return true;

    if (implied && almost)
        return true;

    if (directory && isDot)
        return true;

    return false;
}());

为了保持足够好,您可以随时在此处停止,因为您知道代码简单且高效。


当然……这可以简化。最后一个if 语句可以更改为return

if (a)
    return true;
return false;

转换为:

return a;
include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    if (!dotted)
        return true;

    if (all)
        return true;

    if (implied && almost)
        return true;

    return directory && isDot;
}());

这当然可以通过将最后一个 if 再次转换为 return 来简化:

if (a)
    return true;
return b;

转换为:

return a || b;
include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    if (!dotted)
        return true;

    if (all)
        return true;

    return (implied && almost) ||
        (directory && isDot);
}());

...再一次:

include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    if (!dotted)
        return true;

    return (all) ||
        (implied && almost) ||
        (directory && isDot);
}());

...再一次:

include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    if (directory && !isDot)
        return false;

    return (!dotted) ||
        (all) ||
        (implied && almost) ||
        (directory && isDot);
}());

...再一次:

if (a)
    return false;
return b;

转换为:

return !a && b;
include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    return !(directory && !isDot) && (
        (!dotted) ||
        (all) ||
        (implied && almost) ||
        (directory && isDot)
    );
}());

这可以通过使用De Morgan's laws进一步简化:

!(a && b)

转换为:

!a || !b
include = (function () {
    //set up some simple names for concepts:
    var directory = options.directory;
    var isDot = file === '.';
    var all = options.all;
    var almost = options.almostall;

    return (!directory || isDot) && (
        (!dotted) ||
        (all) ||
        (implied && almost) ||
        (directory && isDot)
    );
}());

你有它,就像逻辑可以得到的一样简单。当然,您可以选择将变量扩展回其原始定义,但我建议您不要这样做。我实际上鼓励您不要简化if..return 语句的简单链。

如果您使代码更简洁,则阅读和理解更具挑战性,这使得调试更具挑战性。很有可能我在“简化”代码时在这篇文章的某个地方犯了一个错误,并且在阅读&&|| 运算符系列时,如果犯了错误,这并不是很明显。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2014-01-21
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多