基本
+加
- 减
乘
/ 除
% 取余
* 指数(ES7新增)
注意!js的除和java不一样,js是5/2=2.5,java是5/2=2
var y = 5 ** 2;//y=25
表达式
一元运算符(自增自减)
++1;
--1;
1++;
1--;
//1.x++、x--;
//相当于先用x的值,再进行下一条语句x=x+1、或者x=x-1;
//2.++x、--x;
//相当于先运算x=x+1、或者x=x-1后,再用x的值;
其他
let s1 = "2";
let s2 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(因为浮点数不精确)
o--; // 值变成-2
位运算符
用于数值的底层操作,也就是操作内存中表示数据的比特(位)
ECMAScript中的所有数值都以 IEEE 754 64 位格式存储,但位操作并不直接应用到 64 位表示,而是先把值转换为32 位整数,再进行位操作,之后再把结果转换为 64 位。
对开发者而言,就好像只有 32 位整数一样.
有符号整数使用 32 位的前 31 位表示整数值。第 32 位表示数值的符号,如 0 表示正,1 表示负
在对 ECMAScript 中的数值应用位操作符时,后台会发生转换:64 位数值会转换为 32 位数值,然后执行位操作,最后再把结果从 32 位转换为 64 位存储起来。
补码
负值以一种称为二补数(或补码)的二进制编码存储。
(1) 确定绝对值的二进制表示(如,对于-18,先确定 18 的二进制表示);
0000 0000 0000 0000 0000 0000 0001 0010
(2) 找到数值的一补数(或反码),换句话说,就是每个 0 都变成 1,每个 1 都变成 0;
1111 1111 1111 1111 1111 1111 1110 1101
(3) 给结果加 1。
1111 1111 1111 1111 1111 1111 1110 1101
1
———————————————————————
1111 1111 1111 1111 1111 1111 1110 1110
那么,-18 的二进制表示就是 11111111111111111111111111101110。要注意的是,在处理有符号整数时,我们无法访问第 31 位。
按位非 ~
对数值取反并减 1
let num1 = 25; // 二进制 00000000000000000000000000011001
let num2 = ~num1; // 二进制 11111111111111111111111111100110
// 或
let num2 = -num1 - 1; //尽管两者返回的结果一样,但位操作的速度快得多。这是因为位操作是在数值的底层表示上完成的。
console.log(num2); // -26
按位与 &
本质上,按位与就是将两个数的每一个位对齐,两个位都是 1 时返回 1,在任何一位是 0 时返回 0。
let result = 25 & 3;
console.log(result); // 1
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
——————————————————————-
= 0000 0000 0000 0000 0000 0000 0000 0001
按位或 |
按位或操作在至少一位是 1 时返回 1,两位都是 0 时返回 0
按位异或 ^
在一位上是 1 的时候返回 1(两位都是 1 或 0,则返回 0)。
左移 <<
所有位向左移动
2 << 5; // 值 2(二进制 10)向左移 5 位,就会得到 64(二进制 1000000)
有符号右移 >>
64 >> 5; // 将 64 右移 5 位,那就是 2
-64 >> 5; // 将 -64 右移 5 位,那就是 -2
无符号右移 >>>
正数操作时,和有符号右移一样。负数时差别很大
let oldValue = -64; // 等于二进制 11111111111111111111111111000000
let newValue = oldValue >>> 5; // 等于十进制 134217726
逻辑(重要)
普通逻辑
&& 与
如果有一个操作数是 null,则返回 null。
如果有一个操作数是 NaN,则返回 NaN。
如果有一个操作数是 undefined,则返回 undefined。
|| 或
! 非
//优先级:与>或>非
1、执行顺序
console.log(1 && 2);
// 输出为2,为什么是2?因为逻辑运算的结果,是决定整个表达式的子表达式的值。
// 因为前面是1无法判断整个表达式是否结束,要判断后面的,因此得到的就是后面的值
console.log(1 || 2);
// 结果为1,因为判断左边那个就已经可以确定得到true了,因此不用去看右边的。
var obj = {
name:"YJL",
run:function(){
console.log("我会跑步");
}
}
// 利用这个行为,可以避免给变量赋值 null 或 undefined。比如:
let myObject = preferredObject || backupObject;
var abb = obj.name || obj.run;
// 下面的空值合并运算符 ?? 也是这样的效果
// 下面的逻辑赋值也是这样的效果
2、执行函数不报错
var obj = {
name:"YJL",
run:function(){
console.log("我会跑步");
}
}
obj.run && obj.run();
//如果函数obj.run 存在的话,就会执行obj.run()。避免了函数不存在导致报错
逻辑赋值(ES12)
相当于逻辑比较后再赋值
或:左边有的情况下用左边的,没有就用右边的,赋值给左边
与:左边右边都存在的情况下,执行右边的,然后把返回值赋值给左边的,否则就什么都不做
比较
大于
< 小于
>= 大于等于
<= 小于等于
== 是否想等
=== 是否全相等
!= 不等
自动转换
console.log("A" < "a"); //true,字符串相比,会逐个比较字母的字符的编码,编码小的就小
let result = "B".toLowerCase() < "b".toLowerCase(); // false,可以全部提升或降低来比
let result = "23" < "3"; // true
如果操作数都是数值,则执行数值比较。
如果操作数都是字符串,则逐个比较字符串中对应字符的编码(从左到右,比较1个,一般小写字母比大写的大)
let result = "23" < "3"; // true
如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
let result = "a" < 3; // 因为"a"会转换为 NaN,所以结果是 false
如果有任一操作数是对象,则调用其 valueOf()方法,取得结果后再根据前面的规则执行比较。
如果没有 valueOf()操作符,则调用 toString()方法,取得结果后再根据前面的规则执行比较。
比较 NaN 时,无论是小于还是大于等于,比较的结果都会返回 false
尽量用===。
全等===
console.log("2" == 2); //true,自动转换
console.log("2" === 2); //false,连数据类型也判断是否相等
浮点数的相等比较
浮点数在运算过程中会产生误差,因为计算机无法精确表示无限循环小数。要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值:
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
转换成布尔 !!
console.log(!!"blue"); // true
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!""); // false
console.log(!!12345); // true
//相当于使用了Boolean()函数
=====================
其他 *
赋值运算 =
= 赋值
+= 加等
-= 减等
/= 除等
*= 乘等
%= 取余等
左移后赋值(<<=)
右移后赋值(>>=)
无符号右移后赋值(>>>=)
var a =1;
//赋值
a += 1;
//相当于a = a + 1;
好处就是不会改变变量的数据类型。
条件(三元运算符) ? : *
相当于if判断,简写
//(判断条件) ? 执行语句1 : 执行语句2
(2>1)?"是":"不是"
可选链操作符 ?. (ES11) *
正常,如果config没传就报错
在开发中,很容易出现获取某个不存在的属性导致报错(比如服务器返回的数据对象),报错的信息是无法获取undefined的属性grilFriend。如果这样写,对象里面没有就会报错,报错的结果是后面逻辑全部都不会执行,严重的安全隐患。
为了解决这个问题,我们可能会先做判断,很麻烦,尤其是在Vue中给template中加v-if作判断
ES11 提供了可选链,如果后面没有,直接就直接返回undefined,不会报错
?.
判断前一个有没有,有才读取后面的,没有就返回undefined
逗号操作符 ,(ES6)
对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
let a = 1;
let b = (a+=1, 11);
// 相当于
let a = 1;
a+=1;
let b = 11;
这个操作符最常用的一种情况是:for 循环中提供多个参数:
for (var i = 0, j = 9; i <= 9; i++, j--)
document.writeln("a[" + i + "][" + j + "] = " + a[i][j]);
我们偶尔会在一些框架的源码里面看到这样的写法(如下)
var a = {
foo: function() {
console.log(this);
}
};
a.foo(); // a
(0, a.foo)(); // window
// 相当于 a.foo.apply(window)
原因是最后返回的是最后一个参数的值,上面例子也就是function(){console.log(this)},然后在全局的情况下调用,也就是this指向window。
作用是可以安全地在全局的环境下执行,忽略执行的平台(浏览器的全局是window,而Node.JS的全局是{ })
数组 扩展运算符 … (ES6)
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax
数组里面有引用的不行
对象 扩展运算符 与 rest参数(ES9)
空值合并 ?? (ES11)
类似于逻辑或,如果左边的是空值、空字符串、0等,会转换成布尔类型的数据(true、false),就会使用右边的“default value”
但是有个问题,如果我只想用空字符””,或者0,就没办法这样。
而空值合并运算符,更好地解决这个问题,如果左边是undefined或null,才用右边的 0
空值合并赋值(ES12)
和上面空值合并一样,相当于 foo = foo ?? “默认值”