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


1380

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

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

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

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

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

恕我直言,这有点棘手。我可以做得更好吗?


31
2018年的注释: x ?? y语法现在处于第1阶段的提案状态- 无效合并
4

2
现在有一个Babel插件,它包含了这种确切的语法。
乔纳森·苏迪亚曼

10
从2019年开始注意:现在处于第3阶段状态!
丹尼尔·谢弗

3
从2020年1月开始的注释:零散的合并运算符在Firefox 72中是本机可用的,但仍然没有可选的链接运算符。
Kir Kanos

4
无效的合并运算符(x ?? y)和可选的链接运算符(user.address?.street)现在都是第4阶段。以下是对这意味着什么的很好描述: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished
Mass Dot Net

Answers:


2132

更新资料

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

使用前请检查兼容性。


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

var whatIWant = someString || "Cookies!";

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


澄清度

无论第一个操作数的类型如何,如果将其强制转换为Boolean都会导致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"

48
像“ false”,“ undefined”,“ null”,“ 0”,“ empty”,“ deleted”之类的字符串都是真,因为它们是非空字符串。
一些

4
这需要澄清。“”不为空,但被认为是错误的。因此,如果您正在检查一个值是否为null,而它恰好是“”,则将无法正确通过此测试。
ScottKoon

99
值得注意的是,它||返回第一个“ truey”值或最后一个“ falsey”值(如果没有一个值可以为true),并且&&以相反的方式工作:返回最后一个truey值或第一个falsey值。
贾斯汀·约翰逊

19
仅供参考,对于仍在乎的人,如果您使用类型的构造函数对其进行声明,则将0和空字符串的计算结果与null相同。var whatIWant = new Number(0) || 42; // is Number {[[PrimitiveValue]]: 0} var whatIWant = new String("") || "a million bucks"; // is String {length: 0, [[PrimitiveValue]]: ""}
凯文·海德

5
如果myObj或myObj.property是虚假的var value = myObj && myObj.property || ''''则@LuisAntonioPestana 将退回到。
Ates Goral

77
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背景,这将是最自然的解决方案。



13
对于这么晚的添加,我们深表歉意,但我只是想完整地指出,该解决方案确实有一个警告,即它没有短路评估;如果您的参数是函数调用,则无论是否返回其值都将对它们全部进行求值,这与逻辑OR运算符的行为不同,因此值得注意。
Haravikk '17

63

是的,它即将推出。请参阅此处的提案此处的实施状态

看起来像这样:

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

2
现在处于第3阶段,并计划用于下一个TypeScript版本!github.com/microsoft/TypeScript/issues/26578
lautaro.dragan

1
无效的合并运算符(x ?? y)和可选的链接运算符(user.address?.street)现在都是第4阶段。以下是对这意味着什么的很好描述: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished
Mass Dot Net

45

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

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

 var whatIWant = $N(someString, 'Cookies!');

1
alert(null ||'')仍然会警告一个空字符串,我想我实际上很喜欢alert(''||'blah')而不是一个空字符串来警告blah-虽然很高兴知道!(+1)
丹尼尔·谢弗

1
我想我实际上可能更喜欢定义一个函数false(如果(严格地)为null / undefined,true则返回),否则将其与逻辑或一起使用;它可能比许多嵌套函数调用更具可读性。例如$N(a) || $N(b) || $N(c) || d比更具可读性$N($N($N(a, b), c), d)
Bob

布伦特·拉森(Brent Larsen)的解决方案更具通用性
Assimilater

if .. return .. else ... return是三元的完美案例。 return (value === null || value === void 0) ? ifnull : value;
亚历克斯·麦克米兰

15

这里没有人提到过的潜力NaN,对我来说,这也是零价值。所以,我以为我要加两分钱。

对于给定的代码:

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

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

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

如果您使用典型的合并方法(如此处所述),则将获得c,其值为:NaN

var result = coalesce(a,b,c,d,e,f); // result.toString() === 'NaN'

这些对我来说都不对。在我自己的可能与您的世界不同的合并逻辑的小世界中,我认为未定义,空值和NaN都是“空值的”。因此,我希望可以d从合并方法取回(零)。

如果任何人的大脑都像我的大脑一样工作,并且您想排除NaN,那么此方法将完成以下任务:

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]
伊西亚·梅多斯

@impinball,您建议的编辑不起作用,它从我的测试用例返回NaN而不是0(零)。从技术上讲,我可以删除该!== 'number'支票,因为我已经评估过它不是nullor undefined,但是这样做的好处是,对阅读此代码的任何人都非常清楚,并且该条件不管顺序如何都可以使用。您的其他建议确实会稍微缩短代码,因此我将使用这些建议。
凯文·尼尔森

2
@impinball,我在建议的编辑中找到了您的错误,您将其保留为arg !== arg,但是您需要将其保留为arg === arg...然后它可以工作。但是,这样做的缺点是您不清楚自己在做什么...需要在代码中添加注释,以防止下一个经过该代码并认为arg === arg多余的人将其删除...但是我会提出来无论如何。
凯文·尼尔森

接得好。顺便说一下,这是利用NaN!== NaN这一事实来检查NaN的快速方法。如果您愿意,可以解释一下。
伊西亚·梅多斯

1
检查“不是数字”可以用内置函数代替:isNaN()
Yury Kozlov

5

当心JavaScript的null定义。在javascript中,“ no value”有两个定义。1. Null:当变量为null时,表示它不包含任何数据,但是该变量已在代码中定义。像这样:

var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts

在这种情况下,变量的类型实际上是对象。测试一下。

window.alert(typeof myEmptyValue); // prints Object
  1. 未定义:如果之前未在代码中定义变量,并且不出所料,则该变量不包含任何值。像这样:

    if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
    // alerts

在这种情况下,变量的类型为“未定义”。

请注意,如果您使用类型转换比较运算符(==),JavaScript将对这两个空值均起同样的作用。为了区分它们,请始终使用类型严格的比较运算符(===)。


1
实际上,null是一个值。这是Object类型的特殊值。变量设置为null意味着它包含数据,该数据是对null对象的引用。可以使用代码中未定义的值来定义变量。这与未声明的变量不同。
Ates Goral

是否声明变量之间的实际差异:alert(window.test)/ * undefined * /; alert(窗口中的“ test”)/ * false * /; window.test =未定义; alert(window.test)/ *未定义* /; alert(窗口中的“测试”)/ * true * /; for(窗口中的var p){/ * p可以是“ test” * /}
Ates Goral

1
但是,您可以使用一个不确定的值(有点矛盾)来定义一个变量var u = undefined;
Serge

@AtesGoral重新为空。尽管您说的是正确的,但按照惯例,“ null”表示“缺少(有用的)数据”。因此,它被认为是“无数据”。并且不要忘记这是对“空合并运算符”的回答。在这种情况下,null绝对被视为“无数据”-不管它在内部如何表示。
ToolmakerSteve

4

阅读您的说明后,@ Ates Goral的答案提供了如何在JavaScript中使用C#执行相同的操作。

@Gumbo的答案提供了检查null的最佳方法;但是,重要的是要注意JavaScript =====JavaScript之间的区别,尤其是在涉及检查undefined和/或问题时null

有关于两个词的区别一个真正的好文章在这里。基本上,请理解,如果您使用==而不是===,JavaScript将尝试合并您正在比较的值,并合并返回比较的结果。


关于该文章(和Jash),困扰我的一件事是,由于某种原因,未定义的window.hello属性被评估为null。应该改为未定义。试用Firefox错误控制台,亲自体验一下。
Ates Goral

3

请注意,React的create-react-app工具链自版本3.3.0(发布于2019年12月5日)以来支持空合并。从发行说明中:

可选链接和空位合并运算符

现在,我们支持可选的链接和无效合并运算符!

// Optional chaining
a?.(); // undefined if `a` is null/undefined
b?.c; // undefined if `b` is null/undefined

// Nullish coalescing
undefined ?? 'some other default'; // result: 'some other default'
null ?? 'some other default'; // result: 'some other default'
'' ?? 'some other default'; // result: ''
0 ?? 300; // result: 0
false ?? true; // result: false

create-react-app也就是说,如果您使用3.3.0+,则可以立即在React应用程序中使用null-coalesce运算符。


3

是的,它的建议是现在的第四阶段。这意味着该提案已准备好包含在正式的ECMAScript标准中。您已经可以在Chrome,Edge和Firefox的最新桌面版本中使用它,但是我们将不得不等待更长的时间,直到此功能实现跨浏览器的稳定性为止。

看下面的示例来演示其行为:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = undefined;
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);

上一个示例等效于:

const var1 = undefined;
const var2 = "fallback value";

const result = (var1 !== null && var1 !== undefined) ?
    var1 :
    var2;
console.log(`Nullish coalescing results in: ${result}`);

需要注意的是nullish凝聚不会威胁falsy值的方式,||运营商做了(只用于检查undefinednull值),因此,下面的代码片段会采取行动如下:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = ""; // empty string
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);


对于TypesScript用户,从TypeScript 3.7开始,该功能现在也可用。


2

希望它将很快以Javascript形式提供,因为它处于2020年4月的提议阶段。您可以在此处监视状态的兼容性和支持-https://developer.mozilla.org/zh-CN/docs/Web/ JavaScript /参考/运算符/ Nullish_coalescing_operator

对于使用打字稿的人,你可以使用nullish合并运算打字稿3.7

从文档-

您可以考虑使用此功能- ??运算符-作为在处理null或时“退回”默认值的方法undefined。当我们写像

let x = foo ?? bar();

这是一种新的表示值foo将在“存在”时使用的方式;但是当它是null或时undefined,请计算bar()其位置。


0

确定正确的答案

它是否存在于JavaScript中? 是的,它确实。 但。当前处于第3阶段2020-02-06,目前尚未在所有地方获得支持。单击下面URL中的链接,然后转到“规格”和“浏览器兼容性”标题,以获取有关其位置的更多信息。

引用自:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

空合并运算符(??)是一个逻辑运算符,当其左侧操作数为null或未定义时返回其右侧操作数,否则返回其左侧操作数。

与逻辑OR(||)运算符相反,如果左操作数是一个不为null或未定义的虚假值,则将其返回。换句话说,如果您使用|| 要为另一个变量foo提供一些默认值,如果您认为某些虚假值可用(例如''或0),则可能会遇到意外行为。请参阅下面的更多示例。

想要例子吗?按照我发布的链接,它包含了所有内容。



MDN链接很有帮助,但这是重复的答案。您应该在沃恩的回答下发表评论。
克里斯

@Chris他的回答还不够,因此我的回答是不够的。
卡尔·莫里森

0

现在,它已在主要版本的主流浏览器(如Chrome,Edge,Firefox,Safari等)的最新版本中提供全面支持。这是null运算符和Nullish合并运算符之间的比较

const response = {
        settings: {
            nullValue: null,
            height: 400,
            animationDuration: 0,
            headerText: '',
            showSplashScreen: false
        }
    };
    /* OR Operator */
    const undefinedValue = response.settings.undefinedValue || 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue || 'Default Value'; // 'Default Value'
    const headerText = response.settings.headerText || 'Hello, world!'; //  'Hello, world!'
    const animationDuration = response.settings.animationDuration || 300; //  300
    const showSplashScreen = response.settings.showSplashScreen || true; //  true
    /* Nullish Coalescing Operator */
    const undefinedValue = response.settings.undefinedValue ?? 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue ?? ''Default Value'; // 'Default Value'
    const headerText = response.settings.headerText ?? 'Hello, world!'; // ''
    const animationDuration = response.settings.animationDuration ?? 300; // 0
    const showSplashScreen = response.settings.showSplashScreen ?? true; //  false
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.