这篇文章 偏基础,一篇查漏补缺的文章。来掘金试试水
闲话少说,开干!!
注意 此篇文章 在浏览器控制台运行(吐槽: 火狐的控制台用的好不得劲!)
基础
加减乘除等基础运算
这里有一些基础的运算符。
+(加)、-(减)、*(乘)、/(除)、
%(取模)、++(自增)、--(自减)、**(幂)。
1+2 //3
2 - 1 //1
1 * 3 //3
4 / 2 //2
5 % 2 //1
// 另外
0 / 0 // NaN
1 / 0 // Infinity
1 / -0 // -Infinity
-1 / 0 // -Infinity
-1 / -0 // Infinity
// 自增和自减需要对变量使用
let a = 1;
a++ //1
a //2
++a //3
a //3
let b = 1;
b-- //1
b //0
--b //-1
b //-1
//幂运算
2**3 //8;
读到这,你可能会想,哇,你这真的水,这么基础都要拿出来说。别急,看完这篇文章你会更坚定你的想法的(哈哈,开玩笑的,慢慢由浅入深,这个意思你懂吧🤓)
- 关于
Math
Math有一些常量,也有一些负责运算的API,比如 . 常量 比如
Math.LN2(2的自然对数)、Math.LN10(10的自然对数)、Math.PI(大名鼎鼎的π)运算API比如
Math.abs(x)(绝对值),Math.ceil(x)(向上取整),Math.floor(x)(向下取整),Math.pow(x, y)(幂) ,Math.sqrt(x)(平方根) ,Math.max([x[, y[, …]]])(最大值),Math.min([x[, y[, …]]])(最小值)等,还有一些 正余弦,正余切,对数运算因为不常用就不举例了。Math.abs(-1) //1 Math.ceil(1.2) // 2 Math.floor(1.2) // 1 Math.pow(2, 3) // 8 Math.sqrt(4) // 2 Math.max(4,2) // 4 Math.max(-4,2) // 2其实上面大部分操作都可以用操作符实现
另外 + 遇到字符串会有拼接的作用,
'hello '+ 'word'; // hello word
也可做一元运算符,有一个类型转换的作用,减法也如此
// 相当于 parseInt 与 parseFloat
+'1' - +'2' // 相当于1-2 = -1
前几天同事推荐了一套题,挺有趣的,可以猛戳 这里⇲ 去自测一波, 中间有这样一道题(还有许多类似的题):
你选啥?
分析 结局总结了我在本测验中涵盖的大部分奇怪的语法。让我们一块一块地分解它:
-""; // -> -0 +"1"; // -> 1 Number(null); // -> 0 Number([,]); // -> 0 //把它们加在一起: -0 + 1 * 0 - 0; // -> 0
中间也涉及到类型转换的一些技巧。
关于类型转换,推荐
语法糖(=、+=、-=、*=、/=、%=)
这里还有一些 结合赋值运算符 = 组合的语法糖
= 是作为很多程序(基本所有)的赋值运算符,把右边的值赋值给左边,不做赘述。
// => 为等价符号
a += b => a = a + b
a -= b => a = a - b
a *= b => a = a * b
a /= b => a = a / b
a %= b => a = a % b
比较运算符与关系运算符
💎比较就是判断相等
主要包含 ==、===、!=、!==
分别是宽松相等和严格相等,宽松不相等和严格不相等
严格判断比宽松多了类型判断
'6' == 6 //true
1 == true //true
undefined == null //true
'6' === 6 //false
1 === true //false
undefined === null //false
💎关系就是比较大小
主要包含 >、<、>=、<=, 很简单。
1 > 2 //false
1 < 2 //true
1 >= 1 //true
1 <= 1 //true
是不是感觉智商受到了侮辱🤡?哈哈哈哈~~
逻辑运算符
主要包含 &&(与,有假取假)、||(或,有真取真,全假取尾)、!(非,取反,布尔值)
可以当做判断来用,也可以取值做个兜底
// ||会把 '' 和 0 当成假值
false || 1 //1
false || 0 //0
9 || false //9
1 && 0 //0
0 && 1 //0
false && '1' //false
'2' && '3' //"3"
!0 //true
!null //true
!undefined //true
!true //false
!-1 //false
三目运算符(a? b:c)
这个简单 ,不过判断规则也是把空字符串 '' 和 0 当成假值
a = a ? a : b;
逗号运算符(,)
逗号操作符 对它的每个操作数求值(从左到右),并返回最后一个操作数的值
var a = 1,b = 2;
a = (1,2,4,9);
a //9
a = (3,b = 5, 8);
a //8
b //5
a = (2, b=6);
a //6
b //6
其实很常见的,大家定义变量也用到过的
let a = 1, b = 2, c = 3;
void 运算符
这个我接触的不多,不过也有一些用处的。
void 运算符 对给定的表达式进行求值,然后返回 undefined。
感觉 void 用的比较少了,下面写的功能是去网上网罗的一些。有点 为赋新词强说愁 的感觉
- 定义空连接
<a href="javascript:void(0);">
这个链接点击之后不会做任何事情,如果去掉 void(),
点击之后整个页面会被替换成一个字符 0。
</a>
- 立即执行函数
这个功能,嗯,,,,怎么说呢,哎~~~
function iife() { console.log('foo') }() // 报错,因为JS引擎把IIFE识别为了函数声明
void function iife() { console.log('foo') }() // 正常调用
~function iife() { console.log('foo') }() // 也可以使用一个位操作符
(function iife() { console.log('foo') })() // 或者干脆用括号括起来表示为整体的表达式
- 箭头函数中避免泄露
注意时避免 doSomething 返回值 泄露出来给箭头函数调用者,感觉有点鸡肋
button.onclick = () => void doSomething();
进阶
数值分隔符(_)
ES2021 引入了数值分割符 _,在数值组之间提供分隔,提升了数值阅读体验
var num = 30_0000_0000 // 30亿
num //3000000000
位运算符
这其实我写这篇文章的初衷,前面写的都当做复习吧。
注意
- 位运算符只能用于整型
- 不适合用于大数值
位运算符涉及二进制运算,语法简洁,能力很大。
复习一下二进制运算?进制转换参考 Number.prototype.toString()⇲
二进制运算
二进制数就是 0, 1 机器码组成的数。咋们平常的看到数是十进制的. 比如 143 ,从低到高位分别是 3,4,1,则143等于
3乘以10的零次方 + 4乘以10的一次方 + 1乘以10的二次方
算式为
3 * 10**0 + 4 * 10**1 + 1 * 10**2 // 143
二进制 1011 就等于
1 * 2**0 + 1 * 2**1 + 0 * 2**2 + 1 * 2**3 // 表示十进制数 11
有点过于基础了,哈哈哈
(15).toString(2) //得到二级制 "1111"
二进制运算有 很多运算 参考 - MDN⇲:
💎&,按位与(全1为1)
在a,b的位表示中,每一个对应的位都为1则返回1, 否则返回0.
15 & 9 // 9
// 1111 & 1001 => 1001
💎|,按位或(有1为1)
在a,b的位表示中,每一个对应的位,只要有一个为1则返回1, 否则返回0.
15 | 9 // 15
// 1111 | 1001 = 1111
💎 ^,按位异或(有异为1)
在a,b的位表示中,每一个对应的位,两个不相同则返回1,相同则返回0.
15 ^ 9 // 1111 ^ 1001 = 0110
💎~,按位非
反转被操作数的位。
~15 //~00000000...00001111 = 11111111...11110000 = -16
注意位运算符“非”将所有的32位取反,而值的最高位(最左边的一位)为1则表示负数(2-补码表示法)
💎<<,左移
将a的二进制串向左移动b位,右边移入0.
15 << 1 // 30,相当于乘以2
// 1111 << 1 = 11110
💎>>,算术右移
把a的二进制表示向右移动b位,丢弃被移出的所有位.
15 >> 1 // 7 相当于除以2再向下取整。
// 1111 >> 1 = 111
💎 >>>,无符号右移
把a的二进制表示向右移动b位,丢弃被移出的所有位,并把左边空出的位都填充为0, 对非负数值,补零右移和带符号右移产生相同结果.
负数用正数的补码表示,原码取反再去补码(+1),比如
1变为-10000 0001 => 1111 1110 => 1111 1111 注意11111111如果当做有符号数(最高位,0正1负)就是 -1 ,无符号数就是 255
15 >>> 1 // 7 相当于除以2再向下取整。
// 1111 >>> 1 = 111
位运算符的使用场景
- 判断奇偶
// 做 & 1运算,结果为1为奇数, 0为偶数
5 & 1 // 1
4 & 1 // 0
- 向下取整
~~ 4.1 //4
~~ 4.7 //4
~~-4.5 //-4
4.5 >> 0 //4
4.8 >> 0 //4
-4.1 >> 0 //-4
-4.1 << 0 //-4
4.8 << 0 //4
// >>> 不可对负数取整
4.8 >>> 0 //4
-4.8 >>> 0 //4294967292
- Number 类型的值交换
// 等同于 es6的 [a,b] = [b,a]
let a = 2, b=3;
a ^= b //1 此时a:1 b:3
b ^= a //2 此时a:1 b:2
a ^= b//3 此时a:3 b:2
- rgb与16进制色值转换
/**
* 16进制颜色值转RGB
* @param {String} hex 16进制颜色字符串
* @return {String} RGB颜色字符串
*/
function hexToRGB(hex) {
var hexx = hex.replace('#', '0x')
var r = hexx >> 16
var g = hexx >> 8 & 0xff
var b = hexx & 0xff
return `rgb(${r}, ${g}, ${b})`
}
/**
* RGB颜色转16进制颜色
* @param {String} rgb RGB进制颜色字符串
* @return {String} 16进制颜色字符串
*/
function RGBToHex(rgb) {
var rgbArr = rgb.split(/[^\d]+/)
var color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3]
return '#'+ color.toString(16)
}
hexToRGB('#ff00ff') // 'rgb(255,0,255)'
RGBToHex('rgb(0,255,255)') // '#00ffff'
- 快排中的取二分数
9 >> 1 //4
6 >> 1 //3
- 判断值是否相等
// 相等 结果为 0 ,否者为 非0
10 ^ 9 //3
9 ^ 9 //0
- 检测是否找到数组项
里用取反(〜)运算符对 -1 以外的任何值,都返回 truthy 值。对它进行非运算,直接 !〜
// 其实includes比这方便。
!!(~arr.indexof(item)) // 找到为true
!!~0 //true
!~-1 //true
!!~1 //true
另外需要注意:
补充
- 整数精度(不使用小数点或指数计数法)最多为15位。小数精度的最大位数是17,但是浮点运算并不总是100% 准确。
- 位运算直接对二进制位进行计算,位运算直接处理每一个比特位,是非常底层的运算,好处是速度极快,缺点是很不直观,许多场合不能够使用。
- 位运算只对整数起作用,如果一个运算数不是整数,会自动转为整数后再运行。
- 在JavaScript内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数
总结: 位运算符 带来的速度肉眼不可见,但理解成本会增加,尽量少用.
空合并运算符(??)
这是为了改善 || 运算符的一些问题(),前面提过 ||会把 '' 和 0 当成假值
详情看代码,falsy 的就只剩下 null 、undefined、false
// 如果全为真值就应该取第一个
1 || 2 //1
0 || 2 //2
'' || 2 //2
0 ?? 2 //0
'' ?? 2 //""
可选链接运算符 (?.)
没有它可能需要这样写:
obj && obj.prop && obj.prop.a
现在只需要
obj??.prop??.a
香的很。和你做个比喻吧,比蚊香还香😁
扩展
这里还有一些起奇妙的运算符,浏览器慢慢把标准落实,这也是很香的东西。
逻辑空分配(??=)
理所当然,可能 会以为 x ??= y 是下面的简写
x = x ?? y
表面的意思就是 x 为 falsy(null, undefined, false) 时 y 就赋值给 x? 代码检测一下
var a = false ?? '赋值成功!' // a 为 false
var a = true ?? '赋值成功!' //a 为 true
这是为啥,因为 合并运算符 ?? 是从左到右操作的, 也就是说 当 左边的赋值操作 (a = false/true)成功后 右边是不会执行的,赋值怎么可能失败呢,对吧
x ??= y 所以相当于
x ?? (x = y)
注意,仅仅是相当于,当然存在一些特殊情况!!!
- 左边值(x)仅当为 nulllish(
null,undefined) 时才会执行!!
function test(val){ var a= val; a ??= '赋值成功!'; return a }
test() //"赋值成功!"
test(1) //1
test(null) //"赋值成功!"
test(false) //false
估计设计它的目的就是为那些 未赋值的变量赋值(null 也被当做未赋值)
逻辑或分配(|| =)
理解了上面的 ??=,这就好理解了嘛,
a ||= b全等于
a || (a = b)
除了代码演示,我无fa可说🙃
function test(val){ var a= val; a ||= '赋值成功!'; return a }
test() //"赋值成功!"
test(0) //"赋值成功!"
test(false) //"赋值成功!"
test(null) // "赋值成功!"
test(undefined) //"赋值成功!"
test('') //"赋值成功!"
场景: 如果a存在默认值,就保存它,不存在就赋新值。
逻辑与分配(&& =)
理解了上面的 ??=,这也好理解了嘛,
a &&= b全等于
a || (a = b)
除了代码演示,我无fa可说🙃
function test(val){ var a= val; a &&= '赋值成功!'; return a }
test(1) // "赋值成功!"
test(0) // 0
test(false) // false
test() // undefined
test(null) // null
test('') // ""
test(NaN) // NaN
场景: 对已经存在的值进行更新
运算符优先级
| Operator type | Individual operators(依次递减) | |
|---|---|---|
| member | . [] | |
| call / create instance | () new | |
| negation/increment | ! ~ - + ++ -- typeof void delete | |
| multiply/divide | * / % | |
| addition/subtraction | + - | |
| bitwise shift | << >> >>> | |
| relational | < <= > >= in instanceof | |
| equality | == != === !== | |
| bitwise-and | & | |
| bitwise-xor | ||
| bitwise-or | ||
| logical-and | && | |
| logical-or | ||
| conditional | ?: | |
| assignment | = += -= *= /= %= <<= >>= >>>= &= ^= | = |
| comma | , |
参考
站在别人肩膀上能看的更远,谢谢💖💖💖以下文章作者~~~
- 🔗 | 表达式与运算符 - MDN
- 🔗 | void 运算符 - MDN
- 🔗 | 一次弄懂Javascript的各种运算符
- 🔗 | 位运算符在JS中的妙用
- 🔗 | 这些 JS 中强大的操作符,总有几个你没听说过
- 🔗 | 25个JavaScript代码简写技巧(下篇)