如何在复杂的布尔表达式上避免三元

How to avoid ternary on complicated boolean expression

在检查我的 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;

正确的 shorthand 实施方式是什么?


试一试:

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

这是正确的吗?

当您使用一堆链式三元运算符编写代码时,它会变得更简洁,而且通常更难阅读。

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

converts to:

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;

converts to:

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;

converts to:

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;

converts to:

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)

converts to:

!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 语句的简单链。

如果您使代码更简洁,那么阅读和理解起来就更具挑战性,从而使调试更具挑战性。很可能我在这个 post while "simplifying" 代码的某处犯了错误,并且在阅读 &&|| 运算符系列时不是很明显,如果犯了错误。