JavaScript-操作符简介
本篇来讲一讲操作符,几乎包含了所有的操作符。内容较多,花了几个晚上写加修改,终于完稿!
你将学到:
一元操作符
`++` 和 `--`
++
自增运算符,如有不是很理解的,可以看看下面这个例子。
let number = 0;
console.log(number++);
console.log(++number);
输出结果是:0
2
解析:
先看 number++
相当于以下两步:
- 先返回0,所以输出0;
- 再计算
number = number + 1
,此时number为1;
++number
:
- 先计算
number = number + 1
,此时number为2; - 再返回2,所以输出2;
--
和 ++
原理是类似的,这里不再赘述
`+` 和 `-`(这里是指正和负)
+
和 -
操作符很好理解,和数学里面的正负是一样的,简单带过
let number = 1;
console.log(+number);//1
console.log(-number);//-1
位操作符
位操作符在实际项目中很少用到,但基于完整性考虑,还是加上来了。
AND(与)
按位与
操作符位:&
第一位 | 第二位 | 按位与 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
规律:位数只有都为1,结果才为1,否则为0
OR(或)
按位或
操作符:|
第一位 | 第二位 | 按位或 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
规律:位数只有都为0,结果才为0,否则为1
NOT(非)
按位非
操作符: ~
位数 | 按位非 结果 |
---|---|
1 | 0 |
0 | 1 |
例子:
let number = 10;
console.log(number.toString(2));//1010
number = ~number;
console.log(number.toString(2));//-1011
注意toString(2)
的意思:将一个10进制数转换为2进制
解析:
10的二进制表示为:
0000 0000 0000 0000 0000 0000 0000 1010
按位非运算后为:
1111 1111 1111 1111 1111 1111 1111 0101
第1位是符号位,1代表负,0代表正
除第1位之外,剩余的位数按位非
1000 0000 0000 0000 0000 0000 0000 1010
最后一位加1
1000 0000 0000 0000 0000 0000 0000 1011
所以最终结果为-1011
注意负数在二进制中的存储是以`二进制的补码`形式存储的一个数的二进制补码是这样计算的:
1. 算出这个数的绝对值的二进制
2. 计算这个二进制的反码
3. 将反码加1
例如,要计算-11的二进制补码:
-11的绝对值11,11的二进制为:
0000 0000 0000 0000 0000 0000 0000 1101
计算反码
1111 1111 1111 1111 1111 1111 1111 0010
将反码加1
1111 1111 1111 1111 1111 1111 1111 0011
所以-11的二进制补码
为:
1111 1111 1111 1111 1111 1111 1111 0011
此时,要计算-11的二进制,将补码除第一位外取反码,得到:
1000 0000 0000 0000 0000 0000 0000 1100
将得到的这个结果再加1即为:
1000 0000 0000 0000 0000 0000 0000 1101
第一位为符号位,1代表负,故结果为-1101
简便公式:~n = -(n + 1)
XOR(异或)
按位异或
操作符:^
第一位 | 第二位 | 按位异或 结果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
规律:位数不相同结果为1,位数相同结果为0
<<(按位左移)
按位左移
将数值的所有位向左移动指定的位数,如下例:
let number = 9;
console.log(number.toString(2));//1001
number = number << 2;
console.log(number);//36,二进制100100
9的二进制
0000 1001
左移2位
0010 0100 十进制的36
前置0被忽略,左移之后,原数值的右侧会多出相应的空位,会补全为0。
注意:左移不会影响原数字的符号位
,-9向左移动2位,结果将是-36
-9的二进制
-1001
左移2位
-100100 十进制的-36
>>(按位右移,有符号)
这个操作符会将数值向右移动相应的位数,但保留符号位,什么意思呢?请看下例:
正数的情况,好理解
let number = 9;
console.log(number.toString(2));//1001
number = number >> 2;
console.log(number);//2,二进制0010
负数的情况,需要注意
let number = -9;
console.log(number.toString(2));//-1001
number = number >> 2;
console.log(number);//-3,二进制-0011
解析:
-9的二进制补码形式(你可以按刚才的规则转换看看,除第一位外其余位取反,然后最后一位加1),注意第1位是符号位
1111 1111 1111 1111 1111 1111 1111 0111
右移2位,注意此时左侧多出的2位空白会补全为符号位
,这就是为什么说右移有符号的原因
1111 1111 1111 1111 1111 1111 1111 1101
第一位不变,其余取反
1000 0000 0000 0000 0000 0000 0000 0010
最后一位加1,结果为-3
1000 0000 0000 0000 0000 0000 0000 0011
>>>(无符号右移)
刚才讲到的>>
是有符号的右移,
>>>
是无符号的右移
二者有什么区别呢?
正数的情况:和>>
结果一样
负数的情况,看下例
let number = -9;
console.log(number.toString(2)); //1001
number = number >>> 2;
console.log(number);//1073741821
结果为什么会这么大呢?
解析:
因为无符号右移(>>>)
在补位时是按0来补位,而有符号右移(>>)
补位时是按符号位来补位,所以
-9的二进制,第1位是符号位
1111 1111 1111 1111 1111 1111 1111 0111
右移2位,此时左侧多出的2位空白会补全为0
0011 1111 1111 1111 1111 1111 1111 1101
此时符号位为0,上面的二进制数的十进制为1073741821
布尔操作符
!(逻辑非)
逻辑非操作符,任何值都可以进行逻辑非运算,返回的是一个布尔值
js中只有以下6个值
undefined
、null
、NaN
、0
、''
(空字符串)、false
的逻辑值为false,
故它们进行逻辑非运算后为true
:
console.log(!undefined);//true
console.log(!null);//true
console.log(!NaN);//true
console.log(!0);//true
console.log(!'');//true
console.log(!false); //true
除以上的6个值外,任何值的逻辑非运算都是false
&&(逻辑与)
逻辑与运算符,此运算符不一定返回的都是逻辑值,只有操作数的值均为逻辑值才返回逻辑值
逻辑值的逻辑与
运算规则如下表:
第一个值 | 第二个值 | 结果 |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
操作数非逻辑值(至少有一个非逻辑值)的逻辑与运算:
此时逻辑与
运算返回的是第一个逻辑值为false
的值,看下例:
console.log(1 && 2); //2
console.log(1 && 0); //0
console.log(2 && 0); //0
console.log(1 && 2 && 0); //0
console.log(0 && 'anything'); //0
console.log(null && 'anything'); //null
解析:
从左往右看,判断每个变量的逻辑值,如果为false
,则返回该值,如果为true
则继续往后判断,直到所有的变量都判断完,此时返回最后一个值,因为只有前面所有的操作数都为true
才有可能判断到最后。
||(逻辑或)
逻辑或运算符,与逻辑与类似,此运算符不一定返回的都是逻辑值,只有操作数的值均为逻辑值才返回逻辑值
逻辑值的逻辑或运算规则如下表:
第一个值 | 第二个值 | 结果 |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
操作数不是逻辑值(至少有一个不是逻辑值)的逻辑或运算:
此时逻辑或
运算返回的是第一个逻辑值为true
的值,看下例:
console.log(1 || 2); //1
console.log(1 || 0); //1
console.log(0 || 2); //2
console.log(0 || 0 || 1); //1
console.log(0 || 'anything'); //anything
console.log(null || 'anything'); //anything
解析:
从左往右看,判断每个变量的逻辑值,如果为true
,则返回该值,如果为false
则继续往后判断,直到所有的变量都判断完,此时返回最后一个值,因为只有前面所有的操作数都为false
才有可能判断到最后,故返回最后一个值。
算术操作符
+
加法运算,Infinity,NaN这些特殊值的操作很少用到,不必太过纠结
- 任何数和NaN加法运算,结果为NaN
- Infinity + Infinity = Infinity
- (-Infinity) + (-Infinity) = -Infinity
- Infinity + (-Infinity) = NaN
console.log(1 + NaN); //NaN
console.log(Infinity + Infinity); //Infinity
console.log((-Infinity) + (-Infinity)); //-Infinity
console.log(Infinity + (-Infinity)); //NaN
这里主要说一下当操作数不是数字的情况
- 任意一个操作数为字符串,那么javascript会将二者拼接起来
console.log('hello' + 'world');//helloworld
console.log('hello' + 123);//hello123
console.log(123 + 'world');//123world
可以看到无论第一个还是第二个数是否为数字,javascript都会将它们拼接起来
- 大于2个操作数的情况
console.log(12 + 3 + 'world');//15world
注意这里,先算术运算再拼接字符串
-
减法运算
- 任何数和NaN减法运算,结果为NaN
- Infinity - Infinity = NaN
- (-Infinity) - (-Infinity) = NaN
- Infinity - (-Infinity) = Infinity
- (-Infinity) - Infinity = -Infinity
console.log(1 - NaN); //NaN
console.log(Infinity - Infinity); //NaN
console.log((-Infinity) - (-Infinity)); //NaN
console.log(Infinity - (-Infinity)); //Infinity
console.log((-Infinity) - Infinity); //-Infinity
当数字和非数字做减法
注意和 +
的区别
console.log(5 - '');//5,
console.log(5 - null);//5
console.log(5 - '1');//4
规则:先将非数字转换为数字,再和数字进行减法运算
*
乘法运算
console.log(1 * NaN); //NaN
console.log(Infinity * 0); //NaN
console.log(Infinity * Infinity); //Infinity
console.log((-Infinity) * (-Infinity)); //Infinity
console.log(Infinity * (-Infinity)); //-Infinity
console.log((-Infinity) * Infinity); //-Infinity
console.log('2' * 2); //4
console.log('-2' * 2); //-4
注意:负负得正,正负得负
,当有一个操作数为非数字时,会将其转为数字后再进行乘法运算。
/
除法运算
console.log(1 / NaN); //NaN
console.log(1 / 0); //Infinity
console.log(-1 / 0); //-Infinity
console.log(Infinity / Infinity); //NaN
console.log(Infinity / 1); //Infinity
console.log(Infinity / (-1)); //-Infinity
console.log(-Infinity / 1); //-Infinity
console.log(-Infinity / (-1)); //Infinity
console.log('2' / 2); //1
console.log('-2' / 2); //-1
注意:当有一个操作数为非数字时,会将其转为数字后再进行乘法运算。
%
取余运算
console.log(1 % NaN); //NaN
console.log(Infinity % Infinity); //NaN
console.log(1 % 0); //NaN
console.log(10 % 3); //1
注意:当有一个操作数为非数字时,会将其转为数字后再进行取余运算。
console.log(10 % '3'); //1
**
幂等运算
a ** b 等价于 Math.pow(a, b)
,a的b次方
console.log(2 ** 3);//8
关系操作符
`>`、`>=` 、`<` 、`<=`、`==`、`!=`
比较运算,返回bool
值
数字比较
console.log(2 > 1); //true
console.log(2 >= 2); //true
console.log(1 < 2); //true
console.log(1 <= 1); //true
console.log(1 == 1); //true
console.log(1 != 2); //true
字符串比较
字符串比较是一个字符一个字符比较,而且区分大小写
console.log('B' > 'A'); //true
console.log('B' > 'a'); //false,'B'的ASCII值为66,'a'的ASCII值为97
console.log('Blue' > 'Blank'); //true
console.log('Blue' > 'Bl'); //true
console.log('23' < '3'); //true
从左至右一个字符一个字符比较它们的ASCII码的值,直到比较到最后一个字符,这里看一看 'Blue’和’Blank’的比较:
1. 第一个字符B,相等,继续判断;
2. 第二个字符l,相等,继续判断
3. 第三个字符u > a,停止比较,'Blue' > 'Blank';
注意当字符串与数字进行比较的时候,字符串会被转换成数字之后再比较。如果字符串无法转换成合法的数字(此时为NaN
),由于NaN
与任何数字比较结果均为false
,故返回false
console.log('23' < 3); //false
console.log('a' < 3); //false
一个关于NaN
有趣的例子:
console.log(NaN < 3);//false
console.log(NaN >= 3);//false
===和!==
===
严格相等,在判断的时候不进行类型转换,什么意思呢?就是说两个操作数进行比较时,不仅要值相等,类型也要相同,最终结果才相等,否则不相等!
!==
严格不等,判断逻辑和===
类似
注意 ===
和 ==
的区别,看下例:
console.log('' == false);//true
console.log('55' == 55);//true
console.log('' != false);//false
console.log('55' != 55);//false
console.log('' === false);//false
console.log('55' === 55);//false
console.log('' !== false);//true
console.log('55' !== 55);//true
这里看一看null
和undefined
的比较:
console.log(null == undefined);//true
console.log(null === undefined);//false
null
和0的比较有点奇怪
console.log(null == 0);//false
console.log(null > 0);//false
console.log(null >= 0);//true
undefined
和0的比较
console.log(undefined > 0);//false
console.log(undefined < 0);//false
console.log(undefined == 0);//false
再看一看NaN
的比较
console.log(NaN == NaN);//false
console.log(NaN != NaN);//true
三元操作符
?
实际项目中,我们经常会写的语句:
let result;
if(a > b){
result = 10;
}else{
result = -10;
}
等价于这样写
let result = a > b ? 10 : -10;
赋值操作符
+=
let a = 10;
a += 2;//等价于a = a + 2, 12
-=
let a = 10;
a -= 2;//等价于a = a - 2, 8
*=
let a = 10;
a *= 2;//等价于a = a * 2, 20
/=
let a = 10;
a /= 2;//等价于a = a / 2, 5
%=
let a = 10;
a %= 2;//等价于a = a % 2, 0
**=
let a = 10;
a **= 2;//等价于a = a ** 2, 100
总结:
操作符是js的基础内容之一,千万不要小看其重要性,下一篇准备写JavaScript的语句方面的内容。
参考:
MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators
写作时间:2020-05-28