【JavaScript笔记(三)】学会JavaScript所有的运算符,看这一篇就够啦!~

一个基本的表达式由运算符操作数组成。运算符根据操作数的数量还可以分为:

  • 一元运算符(只需要一个操作数):正( + )、负( - )、自增( ++ )、自减(- -)、非( ! )

  • 二元运算符(需要两个操作数):加( + )、减( - )、乘( * )、除( / )、取余( % )、指数( ** )、赋值( = )、且( && )、或( || )

  • 三目运算符(需要三个操作数):( ?:)

一. 算数运算符

Number类型之间都可以进行常规的算数运算,非Number类型在强类型语言中是不允许参与运算的。但在JS中可以,JS会把其他数据类型优先转换成数字类型继续运算。
比如:

"12" --> 12  // 纯数字字符串
true --> 1  // boolean
false --> 0  // boolean
null --> 0  // null

也存在无法转换的情况,比如:

'a' --> NaN  // 纯字母字符串
'ab12' --> NaN  // 字母数字字符串
undefined --> NaN  // undefined

1.1 加( + )、减( - )、乘( * )、除( / )

var a = 1 + 1; // 2
var a = 1 + true; // 2
var a = 1 + null; // 1
var a = 1 + undefined; // NaN

在加运算中有一个特殊的设定:当操作数中出现了字符串,加运算就不再执行算术运算了,而是字符串拼接运算。

var a = '1' + 12; // '112'
var a = true + '1'; // 'true1'

var b = '1' + 2 + 3;  // '123'
var c = 1 + 2 + '3';  // '33'

加运算到底是执行数字相加运算,还是执行字符串拼接运算,取决于操作数的类型。也就是说,操作数的类型不同,导致了不同的语法行为,这种现象称为“重载”(overload)

除了加运算,其他算术运算符(比如减法、除法和乘法)都不会发生重载。它们的算法是:所有操作数一律转为数值,再进行相应的数学运算。

var a = 1 - 1; // 0
var a = 1 - true; // 0
var a = 1 - '1'; // 0
var a = 1 - 'a'; // NaN
var a = 1 - null; // 0
var a = 2 * 3; // 6
var a = 2 * false; // 0
var a = 5 / 2; // 2.5

1.2 取余( % )

取余(%)是返回第一个操作数除以第二个操作数所得的余数。

var a = 5 % 2; // 1

还会存在操作数中有负数的情况,这时候结果的正负就取决于第一个操作数的正负。要想得到正确的负数取余结果,可以借助绝对值函数

var a = -5 % 2; // -1
var a = 5 % -2; // 1

 Math.abs(-5 % 2)  // 1

1.3 指数( ** )

指数运算符(**)完成指数运算,前一个操作数是底数,后一个操作数是指数。

2 ** 4 // 16

需要注意的一点是,指数运算符与其他运算符的左结合运算顺序不同,它是右结合。即多个指数运算符连用时,从右向左运算,先进行最右边的计算。

2 ** 3 ** 2  // 512

// 相当于 2 ** (3 ** 2)

1.4 正( + )和负( - )

一元加(减)运算符之后的操作数如果是其他数据类型,则转换为数字类型(作用等同于Number函数)。

+3  // 3
+true  // 1
+'2'  // 1
+'a'  // NaN
+null  // 0
+undefined  // NaN
+[] // 0
+{} // NaN
-3  // -3
-true  // -1
-'2'  // -2
-'a'  // NaN
-null  // -0
-undefined  // NaN
-[] // -0
-{} // NaN

连用两个负数( - )值运算符,等同于正数( + )值运算符,要注意小括号不可少,否则会变成自减运算符( - - )。

-(-true)  // 1

1.5 自增( ++ )和自减(- -)

只要知道自增(++)是本身加一,自减(- -)是本身减一就能适用大部分情况了(逻辑大佬可以多理解一下下述代码第二行为什么结果是 8 )。

var a = 3;
(a++) + (++a);  //  8
a;  // 5

1.6 赋值运算符( = )

赋值运算符顾名思义就是用来给变量赋值的。最常见的赋值运算符当然就是等于号( = )。

var a = 1;  // 将数值 1 赋值给变量 a ,并确定a的数据类型为Number
let b = c;  // 将变量 c 赋值给变量 b

等号的使用方法还有我们熟悉的:

x += y  // 等同于x = x + y

x -= y  // 等同于x = x - y

x *= y  // 等同于x = x * y

x /= y  // 等同于x = x / y

x %= y  // 等同于x = x % y

x **= y  // 等同于x = x ** y

二. 比较运算符

运算结果一般为Boolean类型。常与条件判断语句配合使用。

2.1 > >= < <=

  • 当操作数中有其他类型的值,会先转成数值再比较。
3 > 2  // true
'3' > 2  // true
true < 2  // true
true < false  // false
'2' <= null  // fasle
  • 任何值(包括NaN本身)与NaN比较,返回值都是false。
true >= undefined  // false 
//等价于:1 >= NaN

NaN <= '12'  // false 
//等价于:NaN <= 12

'a' < undefined  // false 
//等价于:NaN < NaN
  • 当操作数都为字符串类型时,会按照字典顺序(Unicode码)进行比较。先比较首字符的 Unicode 码点,如果相等,再比较第二个字符的 Unicode 码点,以此类推。常见字符的Unicode 码点顺序为:数字(0 ~ 9) < 大写字母(A ~ Z) < 小写字母(a ~ z)
'21' > '119'  // true
'helloworld' > 'helloWorld'  // true

拓展一点:Unicode码和ASCII码:

都是计算机编码方式,常用字符的码点顺序相同。
不同的是Unicode是双字节编码,ASCII码是单字节编码,所以ASCII码是八位Byte;Unicode支持全世界的语言(包括汉字),ASCII码只支持拉丁文和一些西欧国家语言(比如我们熟悉的英语)。

'大' > '小'  // false
'上' > '下'  // false
'0' < '零'  // true

2.2 相等(==)和严格相等( === )

2.2.1 相等(==):

  1. 基本数据类型:将操作数转换成同一类型再进行比较;
1 == true  // true
'' == '1'  // false
'' == 0  // true
  1. undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true;
var a;

a == true // false
undefined == 0  // false
false == null  // false

a == null  // true
  1. 引用数据类型:比较两者的引用地址;
var a = {name:"zevin",age:"21"};
var b = {name:"zevin",age:"21"};
var c = a;
a == b  // false
a == c  // true

如果必须比较两个对象的属性值相等呢?
可以把对象序列化之后变成JSON字符串(基本数据类型)再比较。

JSON.stringify(a) == JSON.stringify(b)  // true
                     |
                     v
'{"name":"zevin","age":"21"}'  == '{"name":"zevin","age":"21"}'

2.2.2 严格相等(===)

  1. 先比较两个操作数的类型,若不一致,直接返回false;当两个操作数类型一致时才会继续比较两者的值。
1 == '1'  // true
1 === '1' // false
  1. null,undefined都与自身严格相等;两个只声明未赋值的变量是相等的。
null === null 
undefined === undefined

var a;
var b;
a === b  // true
// 等价于:undefined === undefined
  1. 还有一些特殊的点:
    比如十进制的1和十六进制的1是严格相等的;
    NaN与任何类型都不严格相等;
    正0等于负0。
1 === 0x1 // true
NaN === NaN // false
+0 === -0  // true

2.3 不相等(!=)和严格不相等(!==)

对应的还会有这两个不相等的运算符,都是先求相等运算符的结果,然后返回相反值。

1 != '1'  // false  等同于:!(1 == 1)
1 !== '1'  // true  等同于:!(1 === 1)

三. 逻辑运算符(短路运算符)

3.1 与(&&)

  1. 同真则真,有假则假:
true && true // true
true && false // false
  1. 短路运算原理:
var gender = 'female';
if(gender === 'male' && age > 18{ 

}

对于以上代码,gender === 'male'运算结果为false,整个表达式的值就已经确定为false,不需要再判断第二个表达式,有表达式没有执行这就是短路运算的原理。

我们可以简单验证一下短路原理:

var a = 1;
null && ( a += 1) // null
a // 1  
//直接返回null,(a += 1)并没有执行

拓展一点:
第二个表达式age > 18真的没有执行吗?如何证明?

var gender = 'female';
var age = 13;

function foo(gender){
      console.log('比较性别');
      return gender == 'male';
};
function bar(age){
      console.log('比较年龄');
      return age > 12;
};
if(foo(gender)&& bar(age)){
      console.log('hello boy');
};


输出结果:

比较性别

这样定义两个函数,判断表达式就会调用对应的函数,然后会输出对应的语句。从输出结果来看,函数bar并没有调用,所以就证明了第二个表达式bar(age)没有执行。

  1. 返回值不一定是Boolean类型:
var b = 3;
'hello' && b > 1 // true
b > 1 && 'hello' // 'hello'
'hello' && null // null
b > 1 && a // undefined
b < 1 && null // false
null && b > 1 // null

先解释一下第二行:
'hello'字符串会转换成true,整个&&表达式的值取决于&&之后的表达式b > 1b > 1是可判断的表达式,值为true,所以同真为真,返回true

其他的例子可以看懂嘛?!?是不是满满的问号???QAQ

这里给大家特别详细的总结了各种情况,示例请看以下表格:

可直接判断为true的条件是3 > 25 > 3
可直接判断为false的条件是5 < 3
不可直接判断而转换成true的条件是3"hello"
不可直接判断而转换成false的条件是nullundefined

示例 第一个表达式 第二个表达式 整个表达式
3 > 2 && 5 > 3 可直接判断
true
可直接判断
true
true
3 > 2 && 5 < 3 可直接判断
true
可直接判断
false
false
3 > 2 && 3
3 > 2 && "hello"
3 > 2 && a
3 > 2 && null
可直接判断
true
不可直接判断 第二个表达式的值
3
"hello"
undefined
null
3 < 2 && 5 > 3
3 < 2 && 5 < 3
3 < 2 && 3
3 < 2 && "hello"
3 < 2 && a
3 < 2 && null
可直接判断
false
短路
无所谓形式
false
3 && 3 > 2
"hello" && 3 > 2
不可直接判断
转换为true
可直接判断
true
true
3 && 5 < 3
"hello" && 5 < 3
不可直接判断
转换为true
可直接判断
false
false
3 && 3
3 && “world"
3 && a
3 && null

"hello” && 3
"hello" && “world”
“hello” && a
"hello" && null
不可直接判断
转换为true
不可直接判断 第二个表达式的值
3
"world"
undefined
null

3
"world"
undefined
null
null && 5 > 3
null && 5 < 3
null && 3
null && "hello"
null && a
null && null

a && 5 > 3
a && 5 < 3
a && 3
a && "hello"
a && a
a && null
不可直接判断
转换为false
短路
无所谓形式
第一个表达式的值
null
null
null
null
null
null

undefined
undefined
undefined
undefined
undefined
undefined

规律可总结如下:

  1. 不管第一个表达式是可以直接判断出来的true,还是字符串等转换成的true,整个表达式的值都取决于第二个表达式:如果第二个表达式是不能直接判断真假的,那么就会直接返回第二个表达式的值;如果第二个表达式可以直接判断真假,真,那就同真则真;假,那就有假则假。

  2. 第一个表达式如果是可直接判断真假的为假,就会造成短路,所以无所谓第二个表达式的形式,直接会返回false;第一个表达式如果是不可直接判断的,而是转换成的false,也会造成短路,也是无所谓第二个表达式的值,但是这个时候返回的是第一个表达式的值,而不是false

3.2 或( | | )

  1. 有真则真,同假则假:
true && false // true
false && false // false
  1. 同样适用于之前逻辑与(&&)的特殊用法:
    给大家举几个例子检测一下:
var a;
a || 3 // 3
3 || a // 3
3 > 2 || null // true
null || "hello" // "hello"
a || 5 < 3 // false

3.3 非( ! )

  1. 非真则假,非假则真:
!true // false
!false // true
!!true // true
!!false // false
  1. 非(!)运算的结果一定是boolean类型。表达式中也可以将其他数据类型转换成boolean类型:
var a;
!a // false
!!a // true
!"hello" // false
!!"hello" // true

四. 三目运算符

表达式1 ? 表达式2 : 表达式3

如果表达式1的值为true,则返回表达式2;如果表达式1的值为false,则返回表达式3。效果类似于if-else语句。区别是if-else语句不存在返回值,三目运算符属于表达式,会有返回值,所以在需要返回值的场景就只能使用三目运算符。

五. 二进制位运算符 *

(位运算仅供了解,实用性不高,本文只介绍前四种( |,&,~,^ ),后续的左移运算符(<<),右移运算符(>>),头部补零的右移运算符(>>>)不做介绍)

二进制位运算符是非常底层的运算,好处是速度极快,缺点是很不直观,许多场合不能使用它们,否则会使代码难以理解和查错。有一点需要特别注意,位运算符只对整数起作用,如果一个操作数不是整数,会自动舍弃小数部分转为整数后再执行

5.1 二进制或运算符( | )

逐位比较两个操作数的二进制数,两个二进制位之中都为0,则结果为0,否则为1。

5 | 6  // 十进制
101 | 110  // 二进制


————OUTPUT————
7
// 111 

function toInt32(x) {
return x | 0;
}

5.2 二进制与运算符( & )

逐位比较两个操作数的二进制数,两个二进制位之中只要有一个位为0,就返回0,否则返回1。

0 | 2  // 十进制
00 | 10  // 二进制


————OUTPUT————
0
// 00 

5.3 二进制否运算符( ~ )

二进制否运算符( ~ )是一元运算符,它的作用是将每个二进制位都变为相反值(0变为1,1变为0)。它的计算过程比较复杂,计算结果可简单记忆为:一个数与自身的取反值相加,等于-1。

~ 5  // 十进制
~~ 3  // 自身
~~ 2.11111 // 取整


————OUTPUT————
-6 
3
2

5.4 二进制异或运算符( ^ )

异或运算符( ^ )是在两个二进制位不同时返回1,相同时返回0。

5 ^ 6  // 十进制
101 ^ 110  // 二进制


————OUTPUT————
3
// 011 

“异或运算”还有一个妙用,连续对两个数a和b进行三次异或运算:a ^ = b ; b ^ = a ; a ^ = b ;可以互换它们的值。这意味着,使用“异或运算”可以在不引入临时变量的前提下,互换两个变量的值。

var a = 1;
var b = 2;

a ^= b, b ^= a, a ^= b;

a // 2
b // 1

5.5 取整操作

这四种二进制位运算符都能用来进行取整操作,其中~~2.111是最快的。

2.111 | 0  // 或运算符
2.111 & 0  // 与运算符
~~2.111  // 否运算符
2.111 ^ 0  // 异或运算符


————OUTPUT————
2
2
2
2

猜你喜欢

转载自blog.csdn.net/JZevin/article/details/107714618