JavaScript 对于 ?. 和 ?? 的认识及理解

1. 可选链操作符 —— ?.

可选链操作符 ( ?. ) 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为空 (nullish ) (null 或者 undefined) 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined

1.1 ?.语法

obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)

1.2 ?.描述

假设我们需要引用一个多层嵌套或单层的object,最原始的做法是:

human.action
human.action.play
  • 如果human == null,对于读取单层Obj,控制台会报:Uncaught TypeError: Cannot read properties of undefined (reading 'action')

  • 如果human == {},对于读取多层嵌套,控制台也会同样报上述错误

如何解决?很好解决,加上判断即可

// 写法一
const human = null;
if (human) {
    
    
  console.log(human.action);
}
// 写法二 - 三目
const human = null;
human ? console.log(human.action) : '';
// 写法三
const human = null;
human && console.log(human.action);

单层Obj 还好,但如果是多层嵌套的Obj,那么这也判断是相当的麻烦

let play = human.action && human.action.play;

为了避免报错,在访问human.action.play之前,要保证 human.action 的值既不是 null,也不是 undefined。如果只是直接访问 human.action.play,而不对 human.action 进行校验,则有可能抛出错误。

于是我们就使用?.来简化,在访问 human.action.play 之前,不再需要明确地校验 human.action 的状态,再并用短路计算获取最终结果。

let play = human.action?.play
  • JavaScript在访问human.action.play会先隐式的检查human.action是不是nullorundefined。若是,则会直接返回undefined
const human = {
    
    }; //若后端接口返回数据为{},而正常是有数据的
console.log(human.action.play); // 直接访问报Uncaught TypeError错误

console.log(human.action?.play); // 使用?.不报错,但会输出undefined
//其等价于
console.log(human.action === null || human.action === undefined ? undefined : human.action.play);

1.3 ?.应用

1. ?.与函数调用
const human = {
    
    };
human.eat(); // Uncaught TypeError: human.eat is not a function

human.eat?.(); // 不报错
2. ?.处理回调函数或事件处理器
// 使用可选链进行函数调用 - 引用自MDN
function doSomething(onContent, onError) {
    
    
  try {
    
    
   // ... do something with the data
  }
  catch (err) {
    
    
    onError?.(err.message); // 如果 onError 是 undefined 也不会有异常
  }
}

3. ?.和表达式
const human = {
    
    
    a: 'a',
  };

  let variable = 'a';

  console.log(human?.['a']); // 输出 a
  console.log(human?.[variable]); // 输出 a
4. ?.和访问数组元素
const human = ['a', 'b', 'c'];
console.log(human?.[2]); // 输出 c

const human = [];
console.log(human?.[2]); // undefined
5. ?.Map
const human = new Map([
    ['first', {
    
     content: 'abcdefg' }],
    ['second', {
    
     content: 'hijklmn' }],
]);

console.log(human.get('first')?.content); // 输出 abcdefg
console.log(human.get('third')?.content); // undefined
6. ?.和短路计算
// 引用自MDN
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // x 将不会被递增,依旧输出 0
7. 连用?.
const person = {
    
    
  name: 'News',
  action: {
    
    
    play: {
    
    
      game: 'csgo',
    },
    watch: '',
  },
  cat: {
    
    
    name: 'lemon',
  },
};

console.log(person.action?.play?.game); // 输出 csgo
8. ?.和空值合并操作符??
const human = null;
console.log(human?.name ?? 'human 为null'); // 输出 human 为 null

2.4 注意

?.不能用于赋值

let object = {
    
    };
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

2. 空值合并运算符 —— ??

空值合并操作符??)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

逻辑或操作符(||不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,''0)时。见下面的例子。

console.log(null ?? 'hello'); // 输出 hello
console.log('' ?? 'hello'); // 输出 空

console.log(null || 'hello'); // 输出 hello
console.log('' || 'hello'); // 输出 hello

2.1 ??语法

leftExpr ?? rightExpr

2.2 ??应用

1. 保证常量/变量不为 null 或者 undefined
let variable;

const val = variable ?? 'val默认值';
2. ??和短路
// 引用自MDN
function A() {
    
     console.log('函数 A 被调用了'); return undefined; }
function B() {
    
     console.log('函数 B 被调用了'); return false; }
function C() {
    
     console.log('函数 C 被调用了'); return "foo"; }

console.log( A() ?? C() );
// 依次打印 "函数 A 被调用了"、"函数 C 被调用了"、"foo"
// A() 返回了 undefined,所以操作符两边的表达式都被执行了

console.log( B() ?? C() );
// 依次打印 "函数 B 被调用了"、"false"
// B() 返回了 false(既不是 null 也不是 undefined)
// 所以右侧表达式没有被执行

2.3 注意

?? 直接与 AND(&&)和 OR(||)操作符组合使用是不可取的。

null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError

但是,如果使用括号来显式表明运算优先级,是没有问题的:

(null || undefined ) ?? "foo"; // 返回 "foo"

3. 参考来源

MDN

猜你喜欢

转载自blog.csdn.net/News777/article/details/126702014
今日推荐