1.空值合并操作符(??)
说明:只有当左侧为 null 和 undefined 时,才会返回右侧的数
值得注意的是 :?? 是忽视 null ,undefined 等错误的值
?? 双问号后面接的就是默认值。 当然是在没有值得时候会默认 ?? 后边的值,但是有了默认值 ,那么 ?? 后的值也就不会在去默认了,也就是变成了 赋默认值。
就跟三元运算 一样,不满足条件的时候会执行 : 后边的值
(let x = 6,y = 2;z = x>y ? x-y : x+y)
空值合并操作符(??)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
与 逻辑或 操作符(||)不同,逻辑或 操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,'' 或 0)时。见下面的例子。
const foo = null ?? 'default string';
console.log(foo);
// expected output: "default string"
const baz = 0 ?? 42;
console.log(baz);
// expected output: 0
const nullValue = null;
const emptyText = ""; // 空字符串,是一个假值,Boolean("") === false
const someNumber = 42;
const valA = nullValue ?? "valA 的默认值";
const valB = emptyText ?? "valB 的默认值";
const valC = someNumber ?? 0;
console.log(valA); // "valA 的默认值"
console.log(valB); // ""(空字符串虽然是假值,但不是 null 或者 undefined)
console.log(valC); // 42
一般使用场景
提供默认值,而不使用 false 值(如空字符串、0 等)。
在处理可能为 null 或 undefined 的变量时,选择性地提供备用值。
可选链操作符(?.)
作用: 就是判断这个对象下的(Object)下的(value)下的(length)是否为 null 或者 undefined,
(如果没有加 ?. ,有的时候会报 length 是 null 的错误,或者说 null length 没有定义,然有了 ?. 就省去了好多麻烦)
当其中一链为 null 或者 undefined 时就返回 undefined,这样即使中间缺少一个属性也不会报错。
可选链操作符( ?. ) 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。'?.' 操作符的功能类似于 ' . ' 链式操作符,不同之处在于,在引用为空(null) 时 (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值
例子:
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName);
// expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined
语法:obj?.prop obj?.[expr] arr?.[index] func?.(args)
例子:
函数调用:
let result = someInterface.customMethod?.();
如果希望允许 someInterface 也为 null 或者 undefined ,那么你需要像这样写 someInterface?.customMethod?.()
可选链与表达式:
let nestedProp = obj?.['prop' + 'Name'];
可选链访问数组:
let arrayItem = arr?.[42];
例子:
let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});
let nameBar = myMap.get("bar")?.name;
在一个不含 bar 成员的 Map 中查找 bar 成员的 name 属性,因此结果是 undefined。
短路计算:
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];
console.log(x); // x 将不会被递增,依旧输出 0
当在表达式中使用可选链时,如果左操作数是 null 或 undefined,表达式将不会被计算
连用可选链操作:
let customer = {
name: "Carl",
details: {
age: 82,
location: "Paradise Falls" // details 的 address 属性未有定义
}
};
let customerCity = customer.details?.address?.city;
// … 可选链也可以和函数调用一起使用
let duration = vacations.trip?.getTime?.();
空值合并操作符可以在使用可选链时设置一个默认值:
let customer = {
name: "Carl",
details: { age: 82 }
};
let customerCity = customer?.city ?? "内涵段子";
console.log(customerCity); // “内涵段子”
使用这个运算符,有几个注意点:
(1)短路机制 ( 短路计算 )
a?.[++x] 等同于a == null ? undefined : a[++x] 上面代码中,如果 a 是 undefined 或 null,那么 x 不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。
(2)括号的影响
(a?.b).c 等价于 (a == null ? undefined : a.b).c 上面代码中,?. 对圆括号外部没有影响,不管 a 对象是否存在,圆括号后面的 .c 总是会执行。
一般来说,使用 ?. 运算符的场合,不应该使用圆括号。
(3)右侧不得为十进制数值
为了保证兼容以前的代码,允许 foo ?. 3 : 0 被解析成 foo ?. 3 : 0,因此规定如果 ?. 后面紧跟一个十进制数字,那么 ?. 不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。
(4)可选链与函数调用
调用一个可能不存在的方法时,如果被调用的方法不存在,使用可选链可以使表达式自动返回undefined而不是抛出一个异常。
注:如果存在一个属性名且不是函数, 使用 ?. 仍然会产生一个 TypeError 异常 (x.y is not a function).
使用场景:
链式访问对象属性,而不必手动检查每个属性是否存在。
调用可能不存在的函数。
逻辑空赋值(??=)
逻辑空赋值运算符(x ??= y)仅在 x 是空值(null 或 undefined)时对其赋值。
let a
let b = {name:'张三'}
let c = {name:'李四'}
a??=b
c??=b
console.log(a) //{name: '张三'} ,a空置,为其赋值
console.log(c)//{name: '李四'},c不为空,不会重新赋值
使用场景:
在变量没有被赋值或被赋值为 null 或 undefined 时,将默认值分配给变量。
Null 判断运算符
读取对象属性的时候,如果某个属性的值是 null 或 undefined,有时候需要为它们指定默认值。常见做法是通过 || 运算符指定默认值。
const text = data.text || 'Hello, world!'上面的代码都通过 || 运算符指定默认值,但是这样写可能和预期的结果不一致。
开发者的原意是,只要属性的值为 null 或 undefined,默认值就会生效,但是属性的值如果为空字符串或 false 或 0,默认值也会生效。
为了避免这种情况,ES2020 引入了一个新的 Null 判断运算符??。它的行为类似 ||,但是只有运算符左侧的值为 null 或 undefined 时,才会返回右侧的值。
const text = data.text ?? 'Hello, world!'上面代码中,默认值只有在属性值为 null 或 undefined 时,才会生效。
这个运算符的一个目的,就是跟链判断运算符 ?. 配合使用,为 null 或 undefined 的值设置默认值。
const animationDuration = settings?.animationDuration ?? 300上面代码中,settings 如果是 null 或 undefined,就会返回默认值300。
注意
这些运算符在处理可能为 null 或 undefined 的值时非常有用,可以简化代码并提高可读性。然而,需要注意的是,它们是在 ECMAScript 2020 标准中引入的,因此在旧版本的 JavaScript 中可能不被支持。