ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

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

恕我直言,这有点恶心。我能做得更好吗?

2018 年的注释:x ?? y 语法现在处于第 1 阶段提案状态 - nullish coalescing
现在有一个 Babel plugin 包含了这种精确的语法。
2019 年的注意事项:现在是第 3 阶段状态!
2020 年 1 月的注意事项:空值合并运算符在 Firefox 72 中本机可用,但可选链接运算符仍然不可用。
无效的合并运算符 (x ?? y) 和可选的链接运算符 (user.address?.street) 现在都是第 4 阶段。下面是关于这意味着什么的一个很好的描述: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished

5
5 revs, 3 users 67%

更新

JavaScript 现在支持 nullish coalescing operator (??)。当其左侧操作数为 nullundefined 时,它返回其右侧操作数,否则返回其左侧操作数。

旧答案

请在使用前检查兼容性。

C# null 合并运算符 (??) 的 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"

“false”、“undefined”、“null”、“0”、“empty”、“deleted”等字符串都是 true,因为它们是非空字符串。
值得注意的是 || 返回第一个“truey”值或最后一个“falsey”值(如果没有可以评估为 true),而 && 以相反的方式工作:返回最后一个 truey 值或第一个 falsey 值.
@JustinJohnson 提出了一个很好的观点。这个答案比较了所有三个:?? vs || vs &&
m
mpapec
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 背景,这将是最自然的感觉解决方案。


对这么晚的添加表示歉意,但我只是想为了完整起见,该解决方案确实有一个警告,即它没有短路评估;如果您的参数是函数调用,那么无论是否返回它们的值,它们都将被评估,这与逻辑 OR 运算符的行为不同,因此值得注意。
v
vaughan

是的,它很快就会到来。请参阅 proposal hereimplementation status here

它看起来像这样:

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

s
sth

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

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

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

alert(null || '') 仍然提醒空字符串,我想我实际上喜欢 alert('' || 'blah') 提醒 blah 而不是空字符串 - 不过很高兴知道! (+1)
我想我实际上可能更喜欢定义一个函数,如果(严格)为 null/undefined 则返回 false,否则返回 true - 将其与逻辑或一起使用;它可能比许多嵌套函数调用更具可读性。例如 $N(a) || $N(b) || $N(c) || d$N($N($N(a, b), c), d) 更具可读性。
I
Inigo

这里没有人提到 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

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

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

如果任何人的大脑都像我一样工作,并且您想排除 NaN,那么这个自定义 coalesce 方法(与 the one posted here 不同)将完成:

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 的事实。您可以在此处阅读更多信息:Why is NaN not equal to 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] 中。
G
Gibolt

逻辑无效分配,2020+ 解决方案

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

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

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

基本示例

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

a ??= true  // true
b ??= true  // true
c ??= true  // false

对象/数组示例

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" }

Browser Support 22 年 1 月 - 89%

Mozilla Documentation


f
faithfull

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

查看以下示例以演示其行为:

// 注意:这仅在您运行上述浏览器的最新版本时才有效 const var1 = undefined; const var2 = "后备值";常量结果 = var1 ??变种2; console.log(`空值合并结果:${result}`);

前面的例子等价于:

常量 var1 = 未定义; const var2 = "后备值";常量结果 = (var1 !== null && var1 !== undefined) ?变量 1:变量 2; console.log(`空值合并结果:${result}`);

请注意,nullish coalescing威胁 falsy 值,就像 || 运算符所做的那样(它只检查 undefinednull值),因此以下代码段的作用如下:

// 注意:这仅在您运行上述浏览器的最新版本时才有效 const var1 = ""; // 空字符串 const var2 = "fallback value";常量结果 = var1 ??变种2; console.log(`空值合并结果:${result}`);

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


这是巨大的!
T
Tom

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

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

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


s
sshow

请注意 JavaScript 特定的 null 定义。 javascript中有两个“无价值”的定义。 1. Null:当一个变量为null时,表示它里面没有数据,但是这个变量已经在代码中定义了。像这样:

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

在这种情况下,变量的类型实际上是 Object。测试它。

window.alert(typeof myEmptyValue); // prints Object

未定义:当一个变量之前没有在代码中定义时,正如预期的那样,它不包含任何值。像这样: if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); } // 警报

如果是这种情况,您的变量的类型是“未定义”。

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


实际上,null 是一个值。它是 Object 类型的特殊值。设置为 null 的变量意味着它包含数据,数据是对 null 对象的引用。可以使用代码中未定义的值定义变量。这与未声明的变量不同。
变量声明与否的实际区别:alert(window.test)/*undefined*/; alert("test" in window)/*false*/; window.test = 未定义;警报(window.test)/*未定义*/; alert("test" in window)/*true*/; for (var p in window) {/*p 可以是“测试”*/}
但是(有点自相矛盾)您可以 define 一个具有 undefined 值的变量 var u = undefined;
@AtesGoral 重新为空。虽然您说的是真的,但按照惯例,“null”代表“缺少(有用的)数据”。因此,它被认为是“无数据”。并且不要忘记这是对“空合并运算符”问题的回答;在这种情况下, null 绝对被视为“无数据”——无论它在内部如何表示。
L
Lars Blumberg

请注意,React 的 create-react-app 工具链支持自 version 3.3.0 (released 5.12.2019) 以来的空合并。从发行说明:

可选链接和空值合并运算符我们现在支持可选链接和空值合并运算符! // 可选链 a?.(); // 如果 `a` 为空,则未定义/未定义 b?.c; // 如果 `b` 为空/未定义,则未定义 // 空值合并未定义 ?? '其他一些默认值'; // 结果:'其他一些默认值' null ?? '其他一些默认值'; // 结果: '一些其他默认值' '' ?? '其他一些默认值'; // 结果:'' 0 ?? 300; // 结果:0 假 ??真的; // 结果:假

这就是说,如果您使用 create-react-app 3.3.0+,您今天就可以在您的 React 应用程序中开始使用 null-coalesce 运算符。


I
Inigo

??与 ||与&&

其他答案都没有比较所有这三个。由于 Justin Johnson's comment 有如此多的选票,并且由于 double question mark vs && in javascript 被标记为与此相同,因此将 && 包含在答案中是有意义的。

首先是受贾斯汀约翰逊评论的启发:

||返回第一个“truey”值,否则返回最后一个值。

&& 返回第一个“假”值,否则返回最后一个值。

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

然后,在实时代码中演示:

让 F1, F2 = null, F3 = 0, F4 = '', F5 = parseInt('非数字 (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 ) // 未定义 (F1) console.log( T1 && T2 ) // 8 (T2) console.log( F1 ?? F2 ?? F3 ?? F4 ?? F5 ?? T1 ) // 0 (F3) console.log( F1 ?? F2) // null (F2)


V
Vandesh

它有望很快在 Javascript 中可用,因为它在 2020 年 4 月处于提案阶段。您可以在此处监控状态以获取兼容性和支持 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

对于使用 Typescript 的人,您可以使用 Typescript 3.7 中的 nullish coalescing operator

从文档 -

你可以想到这个功能 - ??运算符 - 作为在处理 null 或 undefined 时“回退”到默认值的一种方式。当我们编写类似 let x = foo 的代码时?酒吧();这是一种新的说法,当它“存在”时将使用值 foo;但是当它为空或未定义时,计算 bar() 代替它。


R
Rm558

需要支持旧浏览器并具有对象层次结构

body.head.eyes[0]  //body, head, eyes  may be null 

可以用这个,

(((body||{}) .head||{}) .eyes||[])[0] ||'left eye'

A
Amit

话太多,这里有两个项目:

逻辑或

常量 foo = '' || '默认字符串';

控制台.log(foo); // 输出是'默认字符串'

空值合并运算符

常量 foo = '' ?? '默认字符串';

控制台.log(foo); // 输出为空字符串,即 ''

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

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


在释放操作员之前,这次谈话是必要的。但是,由于您的答案比@faithful 的答案差而且在时间上要晚得多,所以我认为您的谈话太多了。
r
rajesh kumar

现在它已全面支持最新版本的主流浏览器,如 Chrome、Edge、Firefox、Safari 等。这里是 null 运算符和 Nullish Coalescing 运算符之间的比较

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

M
Michael Freidgeim

使用 Babel 的人需要升级到最新版本才能使用无效合并 (??):

Babel 7.8.0 默认支持新的 ECMAScript 2020 功能:您不再需要使用预设环境为无效合并 (??)、可选链接 (?.) 和动态 import() 启用单个插件

来自https://babeljs.io/blog/2020/01/11/7.8.0


R
Ran Turner

ECMAScript 2021 启用了两个新功能:

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

让 b = 未定义 ?? 5个;控制台.log(b); // 5

逻辑空赋值 (x ??= y) 运算符,仅在 x 具有空值(空或未定义)时进行赋值。

常量车= {速度:20}; car.speed ??= 5;控制台.log(car.speed); car.name ??= "雷诺";控制台日志(汽车名称);

可以在此处找到有关逻辑空值分配的更多信息https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment

可以在此处找到有关 Nullish 合并运算符的更多信息https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator