JavaScript中是否有"null coalescing"运算符?

Dan*_*fer 1305 javascript operators null-coalescing-operator null-coalescing

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

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

String someString = null;
var whatIWant = someString ?? "Cookies!";
Run Code Online (Sandbox Code Playgroud)

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

var someString = null;
var whatIWant = someString ? someString : 'Cookies!';
Run Code Online (Sandbox Code Playgroud)

这有点ick嘿恕我直言.我可以做得更好吗?

Ate*_*ral 2023

C#null coalescing operator(??)的JavaScript等价物使用逻辑OR(||):

var whatIWant = someString || "Cookies!";
Run Code Online (Sandbox Code Playgroud)

有些情况(下面说明)表明行为与C#的行为不匹配,但这是在JavaScript中分配默认/替代值的一般,简洁的方法.


澄清

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

alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)
Run Code Online (Sandbox Code Playgroud)

这意味着:

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"
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是``|`返回第一个"truey"值或最后一个"falsey"值(如果没有可以评估为true)并且`&&`以相反的方式工作:返回最后一个truey值或第一个falsey一. (94认同)
  • 像"false","undefined","null","0","empty","deleted"这样的字符串都是真的,因为它们是非空字符串. (42认同)
  • 对于仍然关心的任何人来说,如果使用类型的构造函数来声明它,那么0和空字符串的计算方法与空值相同.`var whatIWant = new Number(0)|| 42; //是Number {[[PrimitiveValue]]:0} var whatIWant = new String("")|| "一百万美元"; //是String {length:0,[[PrimitiveValue]]:""}` (18认同)
  • @LuisAntonioPestana`var值= myObj && myObj.property || 如果myObj或myObj.property是假的,那么''将回到'''. (5认同)
  • 这需要澄清.""不是空的,但考虑是假的.因此,如果您正在检查null值并且恰好为"",则它将无法正确通过此测试. (4认同)
  • @Ates Goral:+1和Array.prototype.forEach = Array.prototype.forEach || 功能(......是什么? (2认同)
  • @WesModes这正是那个带着笑脸的"陷阱"的重点. (2认同)
  • 注意原始的真实价值!即var defaultTrue = defaultTrue || true总是会产生true,即使之前定义了defaultTrue,这是唯一的异常,因为:var defaultTrue == undefined?true:defaultTrue; 顺便说一下,你可以用|| 很多次:var x = a || b || C; (2认同)
  • 来自C#世界"C#null合并运算符的JavaScript等价物(??)正在使用逻辑OR(||):"因为你的例子而不是真的:0 || 42; .在这种情况下,我希望null合并返回0.我认为应该改变这个答案的第一行.它误导了C#开发人员试图编写JS.(如果答案没有那么多的票数,我不会那么挑剔:)) (2认同)
  • @NithinChandran这仅适用于预定义的变量。在浏览器环境中,您可以执行以下操作:`window.x || “你好”。 (2认同)
  • @JustinJohnson 提出了一个很好的观点。这个答案比较了这三个:[`??` vs `||` vs `&&`](/sf/answers/4910022981/)。 (2认同)

Bre*_*sen 73

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
Run Code Online (Sandbox Code Playgroud)

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

  • 对这种后期添加表示歉意,但我只想注意完整性,这个解决方案确实有一个警告,即它没有短路评估; 如果你的参数是函数调用,那么无论它们的值是否返回,它们都将被评估**,这与逻辑OR运算符的行为不同,因此值得注意. (13认同)
  • 根据[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for ..),`for(var i in arguments)`不保证迭代顺序. .在#Array_iteration_and_for ...的).另请参阅[为什么JavaScript的For ...循环不推荐用于数组?](http://stackoverflow.com/q/5269757/1468366)和[为什么在数组迭代中使用"for ... in"这么糟糕的主意?] (http://stackoverflow.com/q/500504/1468366). (8认同)

sth*_*sth 45

如果||作为C#的替换??在你的情况下不够好,因为它吞下空字符串和零,你总是可以编写自己的函数:

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

 var whatIWant = $N(someString, 'Cookies!');
Run Code Online (Sandbox Code Playgroud)

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

vau*_*han 45

是的,它即将推出.在此处查看提案实施状态.

它看起来像这样:

x ?? y
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 现在处于第3阶段,并计划用于下一个TypeScript版本!https://github.com/microsoft/TypeScript/issues/26578 (2认同)

Kev*_*son 14

在这里没有人提到潜力NaN,对我来说,这也是一个无效的价值.所以,我以为我会增加两美分.

对于给定的代码:

var a,
    b = null,
    c = parseInt('Not a number'),
    d = 0,
    e = '',
    f = 1
;
Run Code Online (Sandbox Code Playgroud)

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

var result = a || b || c || d || e || f; // result === 1
Run Code Online (Sandbox Code Playgroud)

如果您使用典型的合并方法,如此处发布,您将获得c,其值为:NaN

var result = coalesce(a,b,c,d,e,f); // result.toString() === 'NaN'
Run Code Online (Sandbox Code Playgroud)

这些似乎都不适合我.在我自己的小合并逻辑世界中,可能与你的世界不同,我认为undefined,null和NaN都是"null-ish".所以,我希望d从coalesce方法中恢复(零).

如果任何人的大脑像我一样工作,并且你想要排除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;
}
Run Code Online (Sandbox Code Playgroud)

对于那些希望代码尽可能短,并且不介意有点缺乏清晰度的人,你也可以按照@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;
}
Run Code Online (Sandbox Code Playgroud)

  • @impinball,我在建议的编辑中找到了您的错误,您将其保留为arg!== arg,但您需要将其设为arg === arg ...然后它可以工作。但是,这样做的缺点是不清楚您在做什么……需要在代码中添加注释,以防止被下一个经过代码并认为arg === arg的人删除。但我还是把它放起来。 (2认同)

vas*_*vas 9

??VS ||VS&&

其他答案都没有比较所有这三个。由于Justin Johnson 的评论获得了如此多的选票,并且由于javascript 中的双问号与 &&被标记为与此重复,因此包含&&在答案中是有意义的。

首先,受到贾斯汀·约翰逊评论的启发:

  • ||返回第一个“truey”值,否则返回最后一个值,无论它是什么。

  • &&返回第一个“falsey”值,否则返回最后一个值,无论它是什么。

  • ??返回第一个非空、非未定义的值,否则返回最后一个值,无论它是什么。

然后,用实时代码演示:

let F1,
    F2 = null,
    F3 = 0,
    F4 = '',
    F5 = parseInt('Not a number (NaN)'),
    T1 = 3,
    T2 = 8

console.log( F1 || F2 || F3 || F4 || F5 || T1 || T2 ) // 3 (T1)
console.log( F1 || F2 || F3 || F4 || F5 )             // NaN (F5)

console.log( T1 && T2 && F1 && F2 && F3 && F4 && F5 ) // undefined (F1)
console.log( T1 && T2 )                               // 8 (T2)

console.log( F1 ?? F2 ?? F3 ?? F4 ?? F5 ?? T1 )       // 0 (F3)
console.log( F1 ?? F2)                                // null (F2)
Run Code Online (Sandbox Code Playgroud)


Elm*_*sen 8

目前没有支持,但JS标准化过程正在努力:https://github.com/tc39/proposal-optional-chaining

  • 这有点不同:a .b(如果存在则访问ab),而不是?? b(如果存在,则a,否则b). (4认同)

Tom*_*Tom 5

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

@Gumbo 的答案提供了检查 null 的最佳方法;==但是,重要的是要注意与===JavaScript 中的差异,尤其是在检查undefined和/或的问题时null

这里有一篇关于两个术语之间差异的非常好的文章。基本上,请理解,如果您使用==而不是,JavaScript 将尝试合并您正在比较的值,并返回合并===的比较结果。


far*_*zad 5

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

var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts
Run Code Online (Sandbox Code Playgroud)

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

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

    if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
    // alerts
    
    Run Code Online (Sandbox Code Playgroud)

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

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

  • 实际上,null 是一个值。它是 Object 类型的特殊值。设置为 null 的变量意味着它包含数据,该数据是对 null 对象的引用。可以使用代码中未定义的值来定义变量。这与未声明的变量不同。 (2认同)
  • 然而(有点矛盾)你可以**定义**一个带有**未定义**值`var u = undefined;`的变量 (2认同)

fai*_*ull 5

是的,它的提议现在是第 4 阶段。这意味着该提案已准备好包含在正式的 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}`);
Run Code Online (Sandbox Code Playgroud)

前面的例子相当于:

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

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

需要注意的是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}`);
Run Code Online (Sandbox Code Playgroud)


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


Gib*_*olt 5

逻辑空赋值,2020+ 解决方案

目前正在向浏览器添加一个新的运算符,??=。这将空合并运算符??与赋值运算符结合在一起=

注意:这在公共浏览器版本中还不常见。将随着可用性的变化而更新。

??=检查变量是否未定义或为空,如果已定义则短路。如果不是,则将右侧值分配给变量。

基本示例

let a          // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false
Run Code Online (Sandbox Code Playgroud)

对象/数组示例

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }
Run Code Online (Sandbox Code Playgroud)

浏览器支持21 年 4 月 - 84%

Mozilla 文档