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


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

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

    1.1 ?.语法

    obj?.prop
    obj?.[expr]
    arr?.[index]
    func?.(args)
    
    • 1
    • 2
    • 3
    • 4

    1.2 ?.描述

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

    human.action
    human.action.play
    
    • 1
    • 2
    • 如果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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

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

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

    let play = human.action?.play
    
    • 1
    • 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
    • 2
    • 3
    • 4
    • 5
    • 6

    1.3 ?.应用

    1. ?.与函数调用
    const human = {};
    human.eat(); // Uncaught TypeError: human.eat is not a function
    
    human.eat?.(); // 不报错
    
    • 1
    • 2
    • 3
    • 4
    2. ?.处理回调函数或事件处理器
    // 使用可选链进行函数调用 - 引用自MDN
    function doSomething(onContent, onError) {
      try {
       // ... do something with the data
      }
      catch (err) {
        onError?.(err.message); // 如果 onError 是 undefined 也不会有异常
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    3. ?.和表达式
    const human = {
        a: 'a',
      };
    
      let variable = 'a';
    
      console.log(human?.['a']); // 输出 a
      console.log(human?.[variable]); // 输出 a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    4. ?.和访问数组元素
    const human = ['a', 'b', 'c'];
    console.log(human?.[2]); // 输出 c
    
    const human = [];
    console.log(human?.[2]); // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    6. ?.和短路计算
    // 引用自MDN
    let potentiallyNullObj = null;
    let x = 0;
    let prop = potentiallyNullObj?.[x++];
    
    console.log(x); // x 将不会被递增,依旧输出 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    7. 连用?.
    const person = {
      name: 'News',
      action: {
        play: {
          game: 'csgo',
        },
        watch: '',
      },
      cat: {
        name: 'lemon',
      },
    };
    
    console.log(person.action?.play?.game); // 输出 csgo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    8. ?.和空值合并操作符??
    const human = null;
    console.log(human?.name ?? 'human 为null'); // 输出 human 为 null
    
    • 1
    • 2

    2.4 注意

    ?.不能用于赋值

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

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

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

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

    console.log(null ?? 'hello'); // 输出 hello
    console.log('' ?? 'hello'); // 输出 空
    
    console.log(null || 'hello'); // 输出 hello
    console.log('' || 'hello'); // 输出 hello
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.1 ??语法

    leftExpr ?? rightExpr
    
    • 1

    2.2 ??应用

    1. 保证常量/变量不为 null 或者 undefined
    let variable;
    
    const val = variable ?? 'val默认值';
    
    • 1
    • 2
    • 3
    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)
    // 所以右侧表达式没有被执行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3 注意

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

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

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

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

    3. 参考来源

    MDN

  • 相关阅读:
    2022年Java行业分析报告,全面解析别错过
    小马模拟器 (支持Android系统)
    【Linux篇】之常用命令
    pytorch UserWarningfault grid_sample; Python opencv Qt报Current thread的新解决方法
    行业洞察 | 新零售业态下,品牌电商应如何重塑增长?
    Java作业7-Java异常处理
    谈谈分布式系统中的唯一ID生成
    HSDC和独立生成树相关
    【算法】PTA刷题记录
    Postgresql中ParamListInfoData的作用
  • 原文地址:https://blog.csdn.net/News777/article/details/126702014