运算符
前言(阿喵的话)
运算是程序之本。如果你想成为一名优秀的程序猿,熟练的掌握(精通)程序的运算过程,是必修课!
算数运算符
设: a = 5,b 为运算结果
| 运算符 | 描述 | 例子 | a 运算结果 | b 运算结果 |
|---|---|---|---|---|
| + | 加法 | b = a + 1 | 5 | 6 |
| - | 减法 | b = a - 1 | 5 | 4 |
| * | 乘法 | b = a * 2 | 5 | 10 |
| / | 除法 | b = a / 2 | 5 | 2.5 |
| % | 取余 | b = a % 5 | 5 | 0 |
| ++ | 自增 | b = ++a | 6 | 6 |
| b = a++ | 6 | 5 | ||
| -- | 自减 | b = --a | 4 | 4 |
| b = a-- | 4 | 5 |
运算误差问题
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.7; // 0.7999999999999999
0.3 - 0.2; // 0.09999999999999998
1.5 - 1.2; // 0.30000000000000004
0.8 * 3; // 2.4000000000000004
19.9 * 100; // 1989.9999999999998
0.3 / 0.1; // 2.9999999999999996
0.69 / 10; // 0.06899999999999999
Javascript 的浮点数采用的是 IEEE 754 二进制浮点数算术标准,以 0.1 + 0.2 为例,其计算步骤为:
- 当
0.1 + 0.2计算时,会先转换为二进制,但由于浮点数用二进制表示是无穷,即:
0.1 ===> 0.0001 1001 1001 1001 ...(1001循环)
0.2 ===> 0.0011 0011 0011 0011 ...(0011循环)
IEEE 754标注下的 64 位 双精度浮点数 的 小数部分至多支持 53 位二进制,多余的部分会被截断,所以两者相加后的和是:
0.0100110011001100110011001100110011001100110011001101
双精度浮点数 的 小数部分至多支持 53 位二进制,多余的二进制数字被截断,所以两者相加之后的二进制之和是
- 再将截取的 二进制 转换为 十进制,所以结果为
0.30000000000000004,就与预期产生了误差
小技巧一:转换数字类型
+"100"; // 100
+"-100"; // 100
小技巧二:转换字符串类型
100 + ""; // '100'
解决方案
建议使用 mathjs 或 decimal.js 等 依赖库
关系运算符
设: a = 5
| 运算符 | 描述 | 比较 | 返回值 |
|---|---|---|---|
| == | 等于 | a == 8 | false |
| a == 5 | true | ||
| != | 不等于 | a != 8 | true |
| > | 大于 | a > 8 | false |
| < | 小于 | a < 8 | true |
| >= | 大于或等于 | a >= 8 | false |
| <= | 小于或等于 | a <= 8 | true |
== 与 ===
let a = new Number(1);
let b = 1;
a == b; // true
a === b; // false
===“严格比较运算符” (Strict Equality Operator) 会认为不同类型(的数据) 是不同的
let a = new Number(1);
let b = 1;
console.log(a); // 1
console.log(b); // 1
typeof a; // object
typeof b; // number
逻辑运算符
设: a = 5, b = 10
| 运算符 | 描述 | 详细说明 | 例子 | 返回值 |
|---|---|---|---|---|
| && | 与 and | 运算符两侧条件均成立,返回 true | (a < 10 && b > 8) | true |
| || | 或 or | 运算符两侧有一侧条件成立,返回 true | (a == 5 || b == 5 ) | true |
| ! | 非 not | 条件不成立,返回 true | a != 8 | true |
| 运算符
3 | 4; // 7
4 | 4; // 4
8 | 3; // 11
5.3 | 4.1; // 5
9 | 3455; // 3455
|运算符会将参与运算的数转换为二进制,继而相加,再转换回十进制得到结果
3 | 4; // 011 + 100 = 111 => 7
8 | 3; // 1000 + 011 = 1011 => 11
小技巧:取整
3.1415926 | 0; // 3
-3.1415926 | 0; // -3
位运算符
上述文中
|运算符,属于一种位运算符,其他位运算符还有:
&: 与 and,按位与处理两个长度相同的二进制数,两个相应的二进位都为 1,该位的结果值才为 1,否则为 0|: 或 or,按位或处理两个长度相同的二进制数,两个相应的二进位中只要有一个为 1,该位的结果值为 1~: 取反,取反是一元运算符,对一个二进制数的每一位执行逻辑反操作。使数字 1 成为 0,0 成为 1^: 异或,按位异或运算,对等长二进制模式按位或二进制数的每一位执行逻辑异按位或操作。操作的结果是如果某位不同则该位为 1,否则该位为 0<<: 左移,把 << 左边的运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数,高位丢弃,低位补 0>>: 右移,把 >> 左边的运算数的各二进位全部右移若干位,>> 右边的数指定移动的位数>>>: 无符号右移,与有符号右移位类似,除了左边一律使用 0 补位
| 运算符 | 例子 | 二进制计算过程 | 二进制结果 | 十进制 |
|---|---|---|---|---|
| & | x = 5 & 1 | 0101 & 0001 | 0001 | 1 |
| | | x = 5 | 1 | 0101 | 0001 | 0101 | 5 |
| ~ | x = ~5 | 0101 & 0001 | 0001 | -6 |
| x = 5 ^ 1 | 0101 ^ 0001 | 0100 | 4 | |
| << | x = 5 << 1 | 0101 << 1 | 1010 | 10 |
| >> | x = 5 >> 1 | 0101 >> 1 | 0010 | 2 |
| >>> | x = 2 >>> 1 | 0010 >>> 1 | 0001 | 1 |
小技巧:下标取反
!~"".indexOf(); // true
赋值运算
设: a = 5, b = 10
| 运算符 | 描述 | 实例 | 返回值 |
|---|---|---|---|
| = | 赋值 | a = b | 10 |
| += | 自加 | a += b | 15 |
| -= | 自减 | a-= b | -5 |
| *= | 自乘 | a *= b | 50 |
| /= | 自除 | a /= b | 0.2 |
| %= | 自取余 | b %= a | 0 |
| <<= | 自左移 | a <<= 1 | 10 |
| >>= | 自右移 | a >>= 1 | 2 |
此外,类似的
赋值运算还有>>>=、&=、|=、^=
小技巧:
a++等同于a += 1a--等同于a -= 1a ** 2等同于a * a等同于Math.pow(a, 2)a ** 3等同于a * a * a等同于Math.pow(a, 3)
三元运算符
条件语句 ? exprA : exprB
当
条件语句返回true,则执行exprA,否则执行exprB
let a: number = 5;
let s = a > 10 ? "Jordan" : "Bryant";
嵌套使用
let a: number = 5;
let b: number = 10;
let s = a > 10 ? "Jordan" : b < 5 ? "Bryand" : "James";
小技巧:复杂嵌套时的代码可读性
在多层三元嵌套使用时,为了增加代码可读性,我们可以选择将
从属三元表达式所在的代码块,用()包裹
let s = a > 10 ? "Jordan" : (b < 5 ? "Bryand" : "James");
条件语句
依据不同的条件,以执行不同的代码
if 判断
下述示例中:当
a < 10条件成立时,则执行a++
let a: number = 5;
if (a < 10) {
a++;
}
if ... else 语句
下述示例中:当
a < 10条件成立时,执行a++,否则执行a--
let a: number = 5;
if (a < 10) {
a++;
} else {
a--;
}
if ... else if ... else 多条件判断
下属示例中:当
a < 10时,执行a++;当a == 5时,执行console.log(a);否则,执行a--
let a: number = 5;
if (a < 10) {
a++;
} else if (a == 5) {
console.log(a);
} else {
a--;
}
switch ... case 语句
当存在多条件时,可以选择采用
switch ... case语句进行判断
let a: number = 'Jordan';
swtch(a) {
case 'Bryand':
console.log('Kobe ', a);
break;
case 'Jordan':
console.log('Michael ', a);
break;
case 'Iverson':
console.log('Allen ', a);
break;
default:
console.log('My name is ', a);
}
小贴士:
- 在一个
switch语句中,可以添加任意数量的case语句。每个case后需跟一个要进行比较的值(数据类型也必须相同) - 当遇到
break语句时,switch即刻终止 - 每个
switch语句都可以有一个(可选)default,出现在结尾处。当所有case都匹配不为真时,就会执行default下的代码
循环
本节示例中,会使用下属用例数据
// 数组
const A = ["a", "b", "c"];
// 对象
const S = { a: 1, b: 2, c: 3 };
for 循环
for (let i = 0; i < A.length; i++) {
console.log(i);
}
语法格式:
for (初始化; 执行条件; 递差语句;) {
# 循环体
}
for 语句一般情况下,需要设置 3 个条件,以控制流程:
初始化: 会被优先执行,且仅执行一次。此时,允许你声明并初始化控制循环的变量执行条件: 接下来,在每次循环之初,均会优先判断执行条件。如果条件为true,则执行循环体中的代码;如果为fales,则即可终止循环递差语句: 在单次循环执行完成后,会执行地差语句。递差语句可以为递增,亦可为递减,或其他计算公式;
for ... in 与 for ... of
获取数组 下标
for (let index in A) {
console.log(index); // 0, 1, 2
}
获取对象的 键
for (let key in S) {
console.log(key); // a, b, c
}
获取数组的 值
for (let value of A) {
console.log(value); // a, b, c
}
forEach 与 map
使用 forEach 对数组进行循环操作
A.forEach((value, index, array) => {
console.log(index, value, array); // 下标, 值, 原始数组(便于对其进行修改)
});
map 与 forEach 的区别
forEach的回调函数中 不接受返回值- 而
map的回调函数中,可以接受一个返回值,作为数组对应下标的新值,且不会改变原始数组
A.map((value, index) => {
return value + index;
}); // a0, b1, c2
every 和 some 循环
every 的回调函数中,如果 return 一个 true,则表示循环终止
A.every(value => {
if (value == "b") {
return true;
}
});
some 与 every 恰恰相反,当它的回调函数中 return 一个 false 时,表示循环终止
A.some(value => {
if (value == "b") {
return false;
}
});
while 和 do ... while
闲话少叙,上案例
let a: number = 5;
while (a > 0) {
a--;
}
let a: number = 5;
do {
a--;
} while (a > 0);
上述 2 个 案例的执行过程与结果完全相同
break 与 continue
break与continue语句可以在for和while中使用,包括for ... in、for ... of以及do ... while
break意为 跳出循环(或 终止循环)continue意为 跳过当前循环体(或 跳过本次循环),开始下次循环
break 在 for 中的使用
for (let i = 0; i < A.length; i++) {
if (i == 2) {
break;
}
}
break 在 while 中的使用
let a: number = 5;
while (a > 0) {
if (a == 3) {
break;
}
a--;
}
continue 在 for 中的使用
let count: number = 0;
for (let i = 0; i <= A.length; i++) {
if (i % 2 == 0) {
continue;
}
count++;
}
continue 在 while 中的使用
let a: number = 5;
let count: number = 0;
while (a >= 0) {
a--;
if (a % 2 == 0) {
continue;
}
count++;
}
无限循环
无限循环 即 未设置 或 无法触达终止条件 的循环,也被称为 死循环
for (;;) {}
while (true) {}