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

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

技术背景

在JavaScript编程里,处理变量可能为nullundefined的情况极为常见。为了给这类可能缺失值的变量赋予默认值,各种方法和运算符应运而生。长久以来,开发者用逻辑或运算符||来达成简单的默认值赋值,但该方法也存在缺陷。随着时间流逝,为了更精准地处理nullundefined情形,JavaScript推出了空值合并运算符??

实现步骤

旧方法:使用逻辑或运算符 ||

过去,要给变量指定默认值,通常用逻辑或运算符||。示例如下:

1
var whatIWant = someString || "Cookies!";

这种方法会把所有转为布尔值是false的值都认定为无效值,接着使用第二个操作数。不过,它可能和其他语言(像C#)中的空值合并运算符行为有差异。比如:

1
2
3
4
5
alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true

新方法:使用空值合并运算符 ??

JavaScript如今支持空值合并运算符??。当左侧操作数是nullundefined时,它返回右侧操作数;反之,则返回左侧操作数。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

自定义函数

||运算符不符合需求,可以自定义函数:

1
2
3
4
5
6
7
function $N(value, ifnull) {
if (value === null || value === undefined)
return ifnull;
return value;
}

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

考虑 NaN 的自定义函数

若要排除NaN,可使用以下自定义函数:

1
2
3
4
5
6
7
8
9
10
11
function coalesce() {
var i, 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;
}

逻辑空赋值运算符 ??=

还可使用逻辑空赋值运算符??=,它结合了空值合并运算符??和赋值运算符=。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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"

核心代码

空值合并运算符示例

1
2
3
4
5
6
7
8
9
// 正常使用
const var1 = undefined;
const var2 = "fallback value";
const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);

// 使用旧逻辑实现相同功能
const result_old = (var1!== null && var1!== undefined)? var1 : var2;
console.log(`Nullish coalescing results in: ${result_old}`);

逻辑空赋值运算符示例

1
2
3
4
5
const car = { speed: 20 };
car.speed ??= 5;
console.log(car.speed); // 20
car.name??= "reno";
console.log(car.name); // reno

最佳实践

链式使用空值合并运算符

可链式使用空值合并运算符,按从左到右的顺序选取第一个非null、非undefined的值:

1
const value = first ?? second ?? third ?? "default";

与可选链运算符结合

空值合并运算符常和可选链运算符?.一同使用,用于安全访问对象属性:

1
const undefinedValue = response.settings?.undefinedValue ?? 'some other default';

常见问题

||?? 有何差异?

  • ||会返回第一个“真值”,要是没有真值则返回最后一个值,不管它是什么。
  • ??仅返回第一个非null、非undefined的值,若无此类值则返回最后一个值,不管它是什么。
    示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let F1;
let F2 = null;
let F3 = 0;
let F4 = '';
let F5 = parseInt('Not a number (NaN)');
let T1 = 3;
let T2 = 8;

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

// ?? 示例
console.log(F1 ?? F2 ?? F3 ?? F4 ?? F5 ?? T1); // 0 (F3)
console.log(F1 ?? F2); // null (F2)

NaN 怎么处理?

NaN既非null也非undefined,所以使用??运算符时它不会被当作空值处理。若要把NaN当作空值,就得自定义函数来处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

// 或者使用更简洁的方式
function coalesce_short() {
var i, arg;
for (i = 0; i < arguments.length; i++) {
arg = arguments[i];
if (arg!= null && arg === arg) { // arg === arg 对 NaN 为 false
return arg;
}
}
return null;
}

浏览器兼容性如何?

大多数主流浏览器的较新版本都支持空值合并运算符。你可以通过 Can I Use 查看具体的浏览器兼容性情况。要是需要支持较旧的浏览器,可使用Babel等工具对代码进行编译。Babel 7.8.0 及以上版本默认支持空值合并运算符。


JavaScript中是否有“空值合并”运算符?
https://119291.xyz/posts/is-there-a-null-coalescing-operator-in-javascript/
作者
ww
发布于
2025年5月30日
许可协议