在 ECMAScript 2021(ES12)中,JavaScript 引入了新的逻辑赋值操作符 &&=??=。这些操作符将逻辑运算符与赋值运算符相结合,提供了更加简洁、直观的赋值方式。

虽然已经进入标准比较久了,但是我在实际开发中见到的还比较少,今天我们一起来学习下。

逻辑与赋值操作符 &&=

&&= 的工作原理

&&= 操作符是逻辑与运算符(&&)和赋值运算符(=)的结合。它的作用是:仅当左侧变量为真值(truthy)时,才将右侧的值赋给左侧变量。传统的写法需要使用 if 语句或逻辑运算符,&&= 则提供了更为简洁的方式。

传统写法对比:

// 使用 if 语句
if (x) {
  x = y;
}

// 使用逻辑与运算符
x = x && y;

// 使用 `&&=` 操作符(ES2021)
x &&= y;

真值和假值的概念

在 JavaScript 中,以下值被认为是假值(falsy)

  • false
  • 0
  • '' (空字符串)
  • null
  • undefined
  • NaN

其他所有值都被视为真值(truthy)

示例解析

示例 1:用户登录状态

let isLoggedIn = true;
isLoggedIn &&= getUserData(); // 如果已经登录,获取用户数据

function getUserData() {
  return { name: 'ConardLi', age: 17 };
}

// 结果:isLoggedIn 变为 { name: 'ConardLi', age: 17 }

示例 2:库存更新

let stock = 17;

function sell(quantity) {
  stock >= quantity &&= stock - quantity;
}

sell(5); // stock 为 5
sell(17); // stock 保持为 5,因为 5 >= 17 为 false

在上述示例中,sell 函数仅在库存足够时才减少库存,防止出现负库存的情况。

应用场景

(1)条件更新属性

let config = {
  debugMode: true,
  logLevel: null
};

// 仅当 debugMode 为真时,设置 logLevel
config.debugMode &&= (config.logLevel = 'verbose');

// 结果:config.logLevel 为 'verbose'

(2)链式判断

let user = {
  isActive: true,
  hasMembership: true
};

// 仅当用户活跃且有会员资格时,给予折扣
user.isActive &&= user.hasMembership &&= applyDiscount();

function applyDiscount() {
  return '已应用折扣';
}

// 结果:user.hasMembership 变为 '已应用折扣'

空值合并赋值操作符 ??=

??= 的工作原理

??= 操作符结合了空值合并运算符(??)和赋值运算符(=)。它的作用是:仅当左侧变量为 nullundefined 时,才将右侧的值赋给左侧变量。这有助于在变量未被初始化时提供默认值。

传统写法对比:

// 使用 if 语句
if (options.timeout === null || options.timeout === undefined) {
  options.timeout = 3000;
}

// 使用空值合并运算符
options.timeout = options.timeout ?? 3000;

// 使用 `??=` 操作符(ES2021)
options.timeout ??= 3000;

与其他赋值方式的比较

问题:

  • 逻辑或 || 会将 0''false 等合法值视为需要赋默认值的情况,可能导致意外的结果。
let delay = 0;
delay = delay || 1000; // delay 被误赋值为 1000

解决方案:

  • ??= 仅在变量为 nullundefined 时才赋值,避免了上述问题。
let delay = 0;
delay ??= 1000; // delay 保持为 0

使用三元运算符:

user.name = (user.name !== null && user.name !== undefined) ? user.name : 'Anonymous';

问题: 代码较为冗长,可读性不高。

使用 ??=

user.name ??= 'Anonymous';

优势: 简洁明了,仅在变量为 nullundefined 时才赋值,不影响其他假值。

应用场景

??= 操作符非常适合为可能未定义的变量设置默认值,且不会干扰有效的假值。

示例:

let score = 0;
score ??= 100;    // 保持为 0

let tag = '';
tag ??= 'default'; // 保持为 ''

let active = false;
active ??= true;   // 保持为 false

配置默认参数:

function initializeSettings(settings) {
  settings.theme ??= 'light';
  settings.notificationsEnabled ??= true;
  settings.autoSaveInterval ??= 300;

  return settings;
}

最后

JavaScript 的 &&=??= 操作符为我们提供了更为简洁和精确的赋值方式:

  • &&= 操作符: 仅在左侧变量为真值时才进行赋值,适合用于需要在保持假值的同时,根据真值条件更新变量的场景。
  • ??= 操作符: 仅在左侧变量为 nullundefined 时才进行赋值,适合用于为未定义或空值变量设置默认值的场景。

两个新出的 JavaScript 运算符的更多相关文章

  1. javascript运算符语法概述

    × 目录 [1]个数 [2]优先级 [3]结合性[4]类型[5]规则表 前面的话 javascript中的运算符大多由标点符号表示,少数由关键字表示,它们的语法言简意赅,它们的数量却着实不少.运算符始 ...

  2. JavaScript 运算符

    JavaScript 运算符 JavaScript 运算符用于赋值,比较值,执行算术运算等. JavaScript 算术运算符 算术运算符用于执行两个变量或值的运算. 赋值 y = 5, 以下表格将向 ...

  3. JavaScript运算符有哪些

    JavaScript中的运算符有很多,主要分为算术运算符,等同全同运算符,比较运算符,字符串运算符,逻辑运算符,赋值运算符等.这些运算符都有一些属于自己的运算规则,下面就为大家介绍一下JavaScri ...

  4. JavaScript运算符:递增递减运算符前置和后置的区别

    从两段代码说起 var num1 = 2; var num2 = 20; var num3 = --num1 + num2; var num4 = num1 + num2; console.log(n ...

  5. java基础59 JavaScript运算符与控制流程语句(网页知识)

    1.JavaScript运算符 1.1.加减乘除法 加法:+(加法,连接符,正数)          true是1,false是0    减法:-    乘法:*    除法:/ 1.2.比较运算符 ...

  6. JavaScript运算符:递增和递减(++i,--i 和 i++,i-- 的区别)

    递增和递减操作符直接借鉴自C,而且各有两个版本:前置型 (递增 ++i ,递减 --i )和 后置型 (递增 i++ ,递减 i-- ).书本上对两者的定义是:前置型应该位于要操作的变量之前,而后置型 ...

  7. javaScript运算符学习笔记

    1.赋值运算符 javaScript运算符可以分为简单赋值和复合赋值运算.简单赋值运算是将赋值运算符(=)右边的表达式的值保存到赋值运算符左边的变量中,复合赋值运算则是混合了其他操作(算术运算操作,位 ...

  8. JavaScript 运算符是什么?

    ㈠JavaScript 运算符 ⑴运算符 = 用于赋值. ⑵运算符 + 用于加值. ⑶示例:    向变量赋值,并把它们相加: ; // 向 x 赋值 5 ; // 向 y 赋值 2 var z = ...

  9. JavaScript运算符与流程控制

    JavaScript运算符与流程控制 运算符 赋值运算符 使用=进行变量或常量的赋值. <script> ​ let username = "YunYa"; ​ < ...

  10. JavaScript运算符

    JavaScript运算符 1.算数运算符 设定a = 5. 运算符 描述 例子 结果 + 加 b=a+2 b=7 - 减 b=a-2 b=3 * 乘 b=a*2 b=10 / 除 b=a/2 b=2 ...

随机推荐

  1. Win32 动态库dll

    这两天学习动态库的练习,分享下方法 实例.封装窗口类的两种状态. 1.自定义窗口类QWnd 2.资源模板窗口对话框类 下面是dll的头文件,类的声明 #pragma once #ifndef _CLA ...

  2. LaTeX hyperref 包去掉链接方框

    \usepackage[hidelinks]{hyperref}

  3. 【Python + Appium】之元素定位总结(更新)

    一.ID定位 uiautomatorviewer里面的:resource-id driver.find_element(By.ID,"com.csks.businesses:id/tv_nu ...

  4. IDEA - ruoyi - srpingboot - 离线运行

    前提:有项目对应的repository文件,RY的DB配置正常(mysql新增schema ry, 执行 /sql下的sql文件,同步调整ruoyi-admin下的application-druid. ...

  5. Electron32-ViteOS桌面版os系统|vue3+electron+arco客户端OS管理模板

    基于electron32+vue3 setup+pinia2桌面端os管理解决方案ElectronVue3OS. vue3-electron32-os全新原创Electron32+Vite5+Vue3 ...

  6. .net7(.net core) 依赖注入:从 AddSingleton 注册的类里面访问 AddScoped 的问题

    记录一下以免忘记. 今天从NopCommerce开源项目里面把它的任务调度类拆出来到我的项目用的时候,发现报错,报错信息如下 Some services are not able to be cons ...

  7. 76.最小覆盖子串 Golang实现

    题目描述: 给你一个字符串 s .一个字符串 t .返回 s 中涵盖 t 所有字符的最小子串.如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" . 注意: 对于 t ...

  8. LeetCode 1316. Distinct Echo Substrings (RK哈希)

    题意: 给一个字符串 寻找字符串为(a+a)格式的子串有多少.a+a 格式字符串比如 abcabc, ee 等. 首先O(N^2)枚举子串,然后通过哈希在O(1)复杂度判断子串是否符合要求. RK哈希 ...

  9. 聊聊 HTAP 的前世今生

    随着现代社会大型实时分析应用的逐渐流行,关系型数据库已经难以处理高并发的事务请求.商业层面上,当全球进入数字化时代,数字化技术渗透到各行各业,同时产生了海量数据,数据的存储和应用是企业决策的重要依据之 ...

  10. 简述 JavaScript脚本的执行原理?

    js 是一种动态 . 弱类型 . 基于原型的语言 ,通过浏览器可以直接执行: 当浏览器遇到 <script></script>标记时 , 会执行标记之间的js 代码:然后js ...