JavaScript 中是否有“空合并”运算符?

IT技术 javascript operators null-coalescing-operator null-coalescing
2021-01-13 02:52:30

Javascript 中是否有空合并运算符?

例如,在 C# 中,我可以这样做:

String someString = null;
var whatIWant = someString ?? "Cookies!";

我可以为 Javascript 找出的最佳近似值是使用条件运算符:

var someString = null;
var whatIWant = someString ? someString : 'Cookies!';

恕我直言,这有点令人讨厌。我能做得更好吗?

6个回答

更新

JavaScript 现在支持空合并运算符 (??)当其左侧操作数为nullor 时undefined它返回其右侧操作数,否则返回其左侧操作数。

旧答案

使用前请检查兼容性。


与 C# 空合并运算符 ( ??)等效的 JavaScript使用逻辑 OR ( ||):

var whatIWant = someString || "Cookies!";

在某些情况下(在下面澄清),该行为与 C# 的行为不匹配,但这是在 JavaScript 中分配默认/替代值的通用、简洁的方式。


澄清

无论第一个操作数的类型如何,如果将其转换为布尔值的结果为false,则赋值将使用第二个操作数。请注意以下所有情况:

alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)

这意味着:

var whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
值得注意的是,||返回第一个“真”值或最后一个“假”值(如果没有一个可以评估为真),并且&&以相反的方式工作:返回最后一个真值或第一个假值。
2021-03-23 02:52:30
像 "false"、"undefined"、"null"、"0"、"empty"、"deleted" 这样的字符串都是真,因为它们是非空字符串。
2021-04-09 02:52:30
function coalesce() {
    var len = arguments.length;
    for (var i=0; i<len; i++) {
        if (arguments[i] !== null && arguments[i] !== undefined) {
            return arguments[i];
        }
    }
    return null;
}

var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);

// xyz.val now contains 5

这个解决方案的工作原理类似于 SQL 合并函数,它接受任意数量的参数,如果它们都没有值,则返回 null。它的行为类似于 C# ?? 运算符,因为 ""、false 和 0 被视为 NOT NULL,因此计为实际值。如果您来自 .net 背景,这将是最自然的感觉解决方案。

为这么晚的添加道歉,但我只是想为了完整性注意这个解决方案确实有一个警告,它没有短路评估;如果你的参数是函数调用那么他们将全部被不论其value是否返回,这从逻辑或操作者的行为不同,所以值得一提的评估。
2021-04-08 02:52:30

是的,它很快就会到来。请参阅此处的提案此处的实施状态

它看起来像这样:

x ?? y

例子

const response = {
  settings: {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
  }
};

const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false

如果||作为 C# 的替代品??在您的情况下不够好,因为它吞下了空字符串和零,您可以随时编写自己的函数:

 function $N(value, ifnull) {
    if (value === null || value === undefined)
      return ifnull;
    return value;
 }

 var whatIWant = $N(someString, 'Cookies!');
我想我实际上可能更喜欢定义一个函数,该函数返回falseif(严格地)null/undefinedtrue否则 - 将其与逻辑 or 一起使用;它可能比许多嵌套函数调用更具可读性。eg$N(a) || $N(b) || $N(c) || d$N($N($N(a, b), c), d).
2021-03-17 02:52:30
alert(null || '') 仍然提醒一个空字符串,我想我实际上喜欢 alert('' || 'blah') 提醒 blah 而不是空字符串 - 不过很高兴知道!(+1)
2021-03-31 02:52:30

没有人在这里提到NaN, 这对我来说也是一个空值的潜力所以,我想我会加上我的两美分。

对于给定的代码:

var a,
    b = null,
    c = parseInt('Not a number'),
    d = 0,
    e = '',
    f = 1
;

如果您要使用||运算符,您将获得第一个非假值:

var result = a || b || c || d || e || f; // result === 1

如果您使用新的??(空合并)运算符,您将得到c,其值为:NaN

vas result = a ?? b ?? c ?? d ?? e ?? f; // result === NaN

这些对我来说都不是正确的。在我自己的合并逻辑小世界中,这可能与您的世界不同,我认为 undefined、null 和 NaN 都是“null-ish”。所以,我希望d从合并方法中恢复(零)。

如果有人的大脑像我一样工作,并且您想排除NaN,那么这个自定义coalesce方法(与此处发布的方法不同)将实现这一点:

function coalesce() {
    var i, undefined, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg !== null && arg !== undefined
            && (typeof arg !== 'number' || arg.toString() !== 'NaN') ) {
            return arg;
        }
    }
    return null;
}

对于那些希望代码尽可能短并且不介意有点不清晰的人,您也可以按照@impinball 的建议使用它。这利用了 NaN 永远不等于 NaN 的事实。您可以在此处阅读更多相关内容:为什么 NaN 不等于 NaN?

function coalesce() {
    var i, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg != null && arg === arg ) { //arg === arg is false for NaN
            return arg;
        }
    }
    return null;
}
最佳实践 - 将参数视为类数组,利用 NaN !== NaN(typeof+num.toString() === 'NaN'是多余的),将当前参数存储在变量中而不是arguments[i].
2021-04-05 02:52:30