【ECMAScript系列7.0】 : 运算符

201 阅读8分钟

运算符

1.简介

  • 运算符也叫操作符。通过运算符可以对一个或多个值进行运算,并获取运算结果。

  • 比如:typeof 就是运算符,可以来获得一个值的类型。它会将该值的类型以字符串的形式返回

  • +*/( 都是运算符,而(3+5)/2则是表达式

2.优先级和结合性

  • 从左往右先乘除后加减,有括号先算括号
优先级 运算符 说明 结合性
1 [].() 字段访问、数组索引、函数调用和表达式分组 从左向右
2 ++ -- -~!delete new typeof void 一元运算符、返回数据类型、对象创建、未定 义的值 从右向左
3 *、/、% 相乘、相除、求余数 从左向右
4 +、- 相加、相减、字符串串联 从左向右
5 <<、>>、>>> 左位移、右位移、无符号右移 从左向右
6 <、<=、>、>=、instanceof 小于、小于或等于、大于、大于或等于、是否 为特定类的实例 从左向右
7 ==、!=、===、!== 相等、不相等、全等,不全等 从左向右
8 & 按位“与” 从左向右
9 ^ 按位“异或” 从左向右
10 | 按位“或” 从左向右
11 && 短路与(逻辑“与”) 从左向右
12 || 短路或(逻辑“或”) 从左向右
13 ?: 条件运算符 从右向左
14 =、+=、-=、*=、/=、%=、&=、|=、^=、<、<=、>、>=、>>= 混合赋值运算符 从右向左
15 , 多个计算 按优先级计算,然后从右向左

算术运算符

1.什么是算术运算符?

算术运算符
+ 加、字符串连接
-
*
/
% 获取余数(取余)
() 括号,优先级

2.算术运算符的优先级和结合性

  • * / % 优先级要高于+ -
  • 无论是 + - * / % 都是左结合性(从左至右计算)
let result = 10 % 4;
console.log(result);   >>2

3.注意点

  • 当对非Number类型的值进行运算,会将这些值转换为Number然后再运算
result1 = true + 1;  // 2 = 1 + 1
result2 = true + false; // 1 = 1 + 0
result3 = 1 + null; // 1 = 1 + 0
result4 = 100 - '1' // 99
  • 任何值和NaN做运算的结果都是NaN
  • 任何的值和字符串做加法运算,都会先转换为字符串,然后再做拼串操作
result1 = 1 + 2 + '3'  // 33
result2 = '1' + 2 + 3; // 123
  • 任何值做-*/运算时都会自动转换为Number
  • 取模(取余)运算:m%n = 余数
    • 如果m>n的, 那么就正常取余
    • 如果m<n的, 那么结果就是m
    • 如果n是0, 那么结果就是NaN
    • 取余运算结果的正负性, 取决于m而不是n
let res = -10 % 3;   // -1

赋值运算符

1.什么是赋值运算符?

  • 就是将等号右边的值存储到等号左边的变量中
  • 简单类型:=;复杂类型:+= -= *= /= %=

2.优先级和结合性

  • 赋值运算符的优先级低于算数运算符
  • 右结合性(从右至左的计算)
  • 左边只能放变量, 不能放常量
//由于算数运算符的优先级高于赋值运算符所以会先计算1 + 1, 然后再赋值给res
let res = 1 + 1;

// 由于赋值运算符的结合性是右结合性, 所以会先将3赋值给num2, 然后再将Num2中的值赋值给num1
let num1, num2;
num1 = num2 = 3;

自增自减运算符

1.什么是自增自减运算符?

  • 自增运算符: ++
  • 自减运算符: --
  • 用在变量中,不能用在常量/表达式中

2.自增

  • 自增分成两种:a++++a
  • 对于一个变量自增以后,原变量的值会立即自增1。也就是说,无论是 a++ 还是++a,都会立即使原变量的值自增1。
  • 要注意的是**:a 是变量,而 a++++a 是**表达式
  • a++的值等于原变量的值(a自增前的值)
  • ++a的值等于新值 (a自增后的值)

3.自减:同上

var n1=10;
var n2=20;

var n = n1++; //n1 = 11  n1++ = 10

console.log('n='+n);  // 10
console.log('n1='+n1); //11

n = ++n1 //n1 = 12  ++n1 =12
console.log('n='+n); //12
console.log('n1='+n1); //12

n = n2--;// n2=19 n2--=20
console.log('n='+n); //20
console.log('n2='+n2); //19

n = --n2; //n2=18 --n2 = 18
console.log('n='+n); //18
console.log('n2='+n2); //18

关系运算符

  • 通过关系运算符可以比较两个值之间的大小关系,如果关系成立它会返回true,如果关系不成立则返回false
  • 左结合性(从左至右的运算)
  • > < >= <= 的优先级高于 == != === !==
//正式因为关系运算符是左结合性, 所以不能利用关系运算符来判断区间
let res = 10 > 5 > 3;  // true > 3;  1 > 3
let res = 10 <= 25 <= 20;  // true <= 20  1 <= 20
关系运算符
> 大于
< 小于
>= 大于或等于
<= 小于或等于
== 等于
=== 全等于
!= 不等于
!== 不全等于
  • 对于非数值类型的数据, 会先转换成数值类型, 再进行判断
let res= 1 > true; // 1 > 1
let res= 1 > false;  // 1 > 0
let res= 1 > null;  // 1 > 0
let res= 1 > '10';  // 1 > 10
  • 任何数据和NaN进行比较, 返回值都是false
console.log(10 <= 'hello'); //false
  • 如果参与比较的都是字符串类型, 那么不会转换成数值类型再比较, 而是直接比较字符对应的Unicode编码
    • 比较字符编码时,是一位一位进行比较。如果两位一样,则比较下一位,所以借用它可以来对英文进行排序
    • 因此当我们在比较两个字符串型的数字时,一定一定要先转型,比如 parseInt()
// 比较两个字符串时,比较的是字符串的字符编码,所以可能会得到不可预期的结果
console.log('56'>'123'); //true

console.log('b' > 'a'); // 0062 > 0061

unicode编码转换地址

  • ==符号
    • 这个符号并不严谨,会将不同类型的东西,转为相同类型进行比较
    • 只会判断取值
    • undefined 衍生自 null,所以这两个值做相等判断时,会返回true
    • NaN不和任何值相等,包括他本身
    • 可以通过isNaN()函数来判断一个值是否是NaN
console.log('6'== 6);  >>true
console.log(true == '1');  >>true
console.log(0 == -0);  >>true
console.log(null == 0);  >>false

console.log(undefined == null);  >>true

console.log(NaN == NaN);  >>false

console.log(isNaN(b));  >>false
  • ===符号
    • 如果要保证完全等于,我们就要用三个等号===
    • 全等不会做类型转换
    • 会同时判断取值和数据类型
    • ==的反面是!====的反面是!==
console.log('6' === 6);  >>false
console.log(6 === 6);  >>true

逻辑运算符

  • 分类

    • && 与(且):两个都为真,结果才为真。

    • || 或:只要有一个是真,结果就是真。

    • ! 非:对一个布尔值进行取反。

  • 注意事项

    • 左结合性(从左至右的运算),&& 的优先级高于 ||
    • 能参与逻辑运算的,都是布尔值
  • 逻辑短路

    • JS中的 && 属于短路的与,如果第一个值为false,则不会看第二个值
    • JS中的 || 属于短路的或,如果第一个值为true,则不会看第二个值
    true && alert('hhh');  //hhh
    true || alert('hhh');  //true
    
  • 非布尔值运算

    • 如果对非布尔值进行逻辑运算,则会先将其转换为布尔值,然后再操作, 但返回结果是原值
    var result = 5 && 6;  //true && true
    console.log(result);  //6
    
    • 与运算的返回结果:(以两个非布尔值的运算为例)
      • 如果第一个值为true,则必然返回第二个值(所以说,如果所有的值都为true,则返回的是最后一个值)
      • 如果第一个值为false,则直接返回第一个值
    • 或运算的返回结果:(以两个非布尔值的运算为例)
      • 如果第一个值为true,则直接返回第一个值
      • 如果第一个值为false,则返回第二个值
  • 实际开发(做容错处理 )

// 当成功调用一个接口后,返回的数据为 result 对象。这个时候,我们用变量 a 来接收 result 里的图片资源。通常的写法是这样的:(这里我只是举个例子)

if (result.resultCode == 0) {
	var a = result && result.data && result.data.imgUrl || 'http://img.smyhvae.com/20160401_01.jpg';
}

// 上方代码的意思是,获取返回结果中的result.data.imgUrl这个图片资源;如果返回结果中没有 result.data.imgUrl 这个字段,就用 http://img.smyhvae.com/20160401_01.jpg 作为兜底图片。这种写法,在实际开发中经常用到。

逗号运算符

  • 逗号运算符 ,
    • 在JavaScript中逗号运算符一般用于简化代码
    • 左结合性(从左至右的运算)
    • 优先级是所有运算符中最低的
    • 逗号运算符也是一个运算符, 所以也有运算符结果,逗号运算符的运算符结果就是最后一个表达式的结果:表达式1, 表达式2, 表达式3, ....;
// 利用逗号运算符同时定义多个变量
let a,b;
// 利用逗号运算符同时给多个变量赋值
a = 10,b = 5;

let res = ((1+1),(2+2),(3+3));
console.log(res);  //6

三元运算符 / 条件运算符

  • 语法: 条件表达式 ? 语句1 : 语句2;
    • 如果该值为true,则执行语句1,并返回执行结果
    • 如果该值为false,则执行语句2,并返回执行结果