JavaScript不常见但好用的运算符

简介: JavaScript不常见但好用的运算符

前言

如果我问在JavaScript中,你用到的最常见的运算符是什么,你可能会回答以下几种:

+-*/%=?!&&||><

如果我问你知道但是不常用、不会用的运算符,你可能会回答以下几种:

&|~^,

但以上都不是本文要说的内容,本文要说的是另外几种。

双感叹号!!

它并不能算是一种特殊的运算符,而是对非运算符!的两次连续调用。

对于它没什么好说的,懂得都懂。因为JavaScript具有隐式转换类型,像''0nullundefined会被转换为false。

但在一些源码当中为了好理解,也可能是让代码更加严谨,通常使用双感叹号来将一个的状态强制转换为boolean类型,用于后续更加严谨的判断。

空值合并运算符??

他的用法和||类似,都是在取值时用于判定。

不同的是 ||在前值为false时,才会去运算||后面的值。而??是在前值为 undefinednull 时才会运算后面的值。这也是他叫空值合并运算符的原因。

console.log(null ?? 'default string');  //  "default string"
console.log(undefined ?? 33); // 33
console.log(false ?? 22); // false
console.log("" ?? 11); // ""
console.log(0 ?? 42); // 0

使用场景大家应该都能想得到,和||有些类似,只不过他比||更细致。有点类似于ES6函数形参中默认赋值等于号的用法。

也相当于是对三目的一种省略,看起来也简洁明了一点。

// let person = data.xx ? data.xx : {name: 'NiGuang'}; 三目
let person = data.xx ?? {name: 'NiGuang'};

需要注意的是他不能与 && 或 || 运算符共用, 因为空值合并运算符和其他逻辑运算符之间的运算优先级/运算顺序是未定义的)这种情况下会抛出 [SyntaxError] 。

可选链式运算符?.

首先要注意的是这个运算符不是问号?而是?.,后面多一个点,二者有本质上的区别。

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

当尝试访问可能不存在的对象属性时,可选链运算符将会使表达式更短、更简明。在探索一个对象的内容时,如果不能确定哪些属性必定存在,可选链运算符也是很有帮助的。

看完MDN的介绍还是不太明白?举个小例子告诉你怎么用!

 let grade = {
    data: {
        productList: []
    },
    resp: 'success',
    code: 1000
}
// 以前获取层级深得数据,需要先用if判断每一层是否存在,不然会报错。
console.log(grade.data.productList[0].name);
 // VM2765:9 Uncaught TypeError: Cannot read properties of undefined (reading 'name') at <anonymous>:9:39
 let grade1 = {
    data: {},
    resp: 'success',
    code: 1000
}
/** 使用了可选链式运算符之后直接写,如果在其中一层没找到会自动赋值为undefined,不再向 后查找,避免了使用if进行一层层判断。
*  当接口未按规定返回时,也不会报错阻塞程序导致白屏。
*  当然代价是你要对使用这个值进行判空处理,不然在用的时候undefined还是会报错。
*/
console.log(grade1.data?.productList[0]?.name); // undefined

~~

就这,就这?前面你说的我都见过,并且已经在用了。

那这个你见过吗?

它与前面的双感叹号相同,也不是一个特殊的运算符。而是对单一运算符的连续两次重复调用,即对位运算符~的两次调用。位运算我们不常用,不深入,就主要来看~~的作用。

作用

他可以用来对小数向下取整。

就这,就这?溜了,溜了,说了半天还以为什么东西,我直接Math.floor()完事。

兄弟先别走,如果Math.floor()能解决,那我当然不会说这个了。先说下我遇到他的经历。

经历

最近刷leetcode遇到这样一道题,求一个数的平方根,如果有小数就向下取整。例如8的平方根为2。

这一下给我整高兴了,这用JavaScript实现和 1 + 1等于几有什么区别?于是我就提交了Math.floor(Math.sqrt(x))

提交后显示运行时间为68 ms,击败79.59%的人,大部分人都采用了这种方法。看着这个接近80%的数字,我就在想那20%是用了什么方法比这个还快呢?带着好奇心我点开了用时最少的代码,就看到了~~(Math.sqrt(x))

与Math.floor()的异同

前面说了他是连续两次位运算,又介绍了我遇到他的经历。

那么它比Math.floor()的好处显而易见,那就是快快快。只用了40ms,比Math.floor()整整快了28ms。

负数也是向下取整

第二个区别就是再对负数取整时,Math.floor()是按照数学上的小去取整(负数值越大越小),而~~依然是抹掉零头式取整。

console.log(Math.floor(-2.8)); // -3
console.log(~~-2.8); // -2

>>

这种一看就是个位运算符,他的名字叫右移运算符。如果不是刷leetcode,大概他我也一辈子不会遇到他吧。以下是MDN关于他的介绍:

右移运算符>> )将一个操作数的二进制表示形式向右移动指定位数,该操作数可以是数值或者 BigInt 类型。右边移出位被丢弃,左边移出的空位补符号位(最左边那位)。该操作也称为“符号位传播右移”(sign-propagating right shift)或“算术右移”(arithmetic right shift),因为返回值的符号位与第一个操作数的符号位相同。

看不懂不要紧,在我所见到的场景中,大家使用它最多的地方就是求二分法中间值的索引。

在求中间值时要注意左边是两个数的加和,右边永远是1.

例如下面的例子

// 求(2,7)的中间值
console.log(Math.floor(2 + (7 - 2) / 2));  // 4
console.log(Math.floor((2 + 7) / 2));  // 4
console.log((2 + 7) >> 1);  // 4

同样它的好处依然是 快快快,在leetcode中用时排名靠前的JavaScript算法,基本都使用了位运算。它可以快到帮你超越10%的对手。

前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

相关文章
|
2月前
|
JavaScript
js运算符
js运算符
23 5
|
2月前
|
JavaScript 前端开发
JavaScript 运算符全知道
JavaScript 运算符全知道
55 0
|
3月前
|
JavaScript 前端开发
JavaScript 运算符
JavaScript 运算符
22 3
|
7月前
|
存储 JavaScript 前端开发
【JavaScript技术专栏】JavaScript基础入门:变量、数据类型与运算符
【4月更文挑战第30天】本文介绍了JavaScript的基础知识,包括变量(var、let、const)、数据类型(Number、String、Boolean、Undefined、Null及Object、Array)和运算符(算术、赋值、比较、逻辑)。通过实例展示了如何声明变量、操作数据类型以及使用运算符执行数学和逻辑运算。了解这些基础知识对初学者至关重要,是进阶学习JavaScript的关键。
53 0
|
4月前
|
JavaScript 前端开发
JavaScript 中的 typeof 运算符
【8月更文挑战第29天】
27 1
|
4月前
|
JavaScript 前端开发 安全
深入理解JavaScript中的比较运算符
深入理解JavaScript中的比较运算符
|
4月前
|
前端开发 JavaScript 程序员
聊聊前端 JavaScript 的扩展运算符 “...“ 的使用场景
聊聊前端 JavaScript 的扩展运算符 “...“ 的使用场景
|
4月前
|
JavaScript 前端开发
JS常见的运算符有哪些?
JS常见的运算符有哪些?
|
4月前
|
JavaScript 前端开发
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
这篇文章详细介绍了JavaScript中的强制类型转换、运算符(包括算术、逻辑、条件、赋值和关系运算符)的使用方法和优先级规则。
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
|
5月前
|
JavaScript 前端开发 网络架构
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
JavaScript编码之路【对象的增强、ES6新特性之函数的默认值设置 、rest参数 (剩余参数)、拓展运算符、对象与数组的解构赋值】
60 1