09.JavaScript算术运算符(加、减、乘、除、幂、余)、自增、自减、缩写、位移

JavaScript算术运算符


章节目录
上一篇:《类型转换》
下一篇:《比较运算符》


运算符是数学计算中的概念,我们从小学就在学习的+-*/就是最基础的运算符。

运算符分类

依据参与运算符的操作数的个数,我们习惯上将运算符分为“单目运算符”、“双目运算符”和“三目运算符”。另外一种说法是:“一元运算符”、“二元运算符”和“三元运算符”。

单目运算符

如果一个运算符只操作一个数据,那么它就是单目运算符
负号'-'就是一个单目运算符,它的作用就是对数字进行正负转换:

let x = 1;
x = -x;    //取负值时只操作一个数
alert(x);

双目运算符

如果一个运算符拥有两个操作数,那么它就是双目运算符,例如减号'-'就是双目运算符,需要操作减数和被减数:

let x = 1;
let y = 2;
alert(x - y); //减号操作两个操作数

这里,同样一个减号'-'拥有两种含义,即负号、减号
负号是单目运算符,用于反转数字的符号
减号是双目运算符,用于操作减数和被减数

三目运算符

三目运算符同时操作三个操作数,在JavaScript中只有一种三目运算符:? :

我们会在if else章节详细介绍三目运算符的用法。

算术运算符

算术运算符包括以下几种:

  1. 加法 +
  2. 减法 -
  3. 乘法 *
  4. 除法 /
  5. 求模 % (求余)
  6. 求幂 **(次方)

前面四个基础运算都特别的简单,举例带过:

let x = 1;
let y = 2;
alert(x + y); //3
alert(x - y); //-1
alert(x * y); //2
alert(x / y); //0.5

求模%(取余)

取余数的运算符是%,虽然符号比较奇怪,但实际上和百分号毫无关联。

x % y的意思就是用x整除y的余数。

举个栗子:

let x = 9;
let y = 2;
alert(x % y); // 1
alert(y % x); // 2

求幂**(次方、指数)

幂运算符**用于指数运算,(x**y)指的是xy次方,也就是x y ^y y

举个栗子:

alert(2 ** 3);    // 8
alert(2 ** 0.5);  // 1.414...  √2
alert(0.3 ** 2);  // 0.09

字符串拼接运算符 +

加号'+'运算符,除了简单的算术加和之外,还能以双目运算符的身份参与字符串拼接运算。

举个栗子:

let str1 = "Trump";
let str2 = "Crazy";
let str3 = str1 + str2;//用加号拼接字符串
alert(str3);

加号作为拼接运算符也是上节《类型转换》中字符串不会隐式转换成数字,参与加法运算的原因。

注意

任意一个参与运算的变量是字符串,那么另外一个操作数也会被转换成字符串。

举个栗子:

let num = 996;
let str = "JavaScript";
alert(num + str); // "996JavaScript"
alert(str + num); // "JavaScript996"

这种特性和其他语言稍有区别
例如在C++Java中,数字加字符串会出现类型不兼容错误。

另一种情况:

let num1 = 1;
let num2 = 2;
let str = "JavaScript"
alert(num1 + num2 + str); //(1) "3JavaScript"而不是"12JavaScript"
alert(str + num1 + num2); //(2) "JavaScript12"而不是"JavaScript3"

请注意这里有一些和直觉不同的结果,造成这样结果的原因是表达式的计算都是从左向右进行的。

(1)处的计算是先进行1 + 2 = 3,然后再执行3 + "JavaScript" = "3JavaScript"

(2)处的计算是先进行"JavaScript" + 1 = "JavaScript1",然后再执行"JavaScript1" + 2 = "JavaScript12"

数字转运算符 +

加号同样可以作为单目运算符使用,如果作为正号用在数学运算中,是没有任何作用的:

let num1 = 1;
alert(+num1);
let num2 = -1;
alert(+num2);

但是作为数字转运算符用在非数字类型的变量上,可以起到类型转换的目的:

alert(typeof +"123"); //Number
alert(typeof +true);  //Number
alert(typeof +undefined) //Number
alert(+"123"); //123
alert(+true);  //1
alert(+undefined) //NaN

'+'以单目运算符的身份用在非数字类型变量上,就能产生和类型转换函数Number(...)同样的效果,但是更加简洁。

例如,使用加号实现字符串的数学运算:

let x = "1";
let y = "2";
alert(x + y);     //字符串拼接'12'
alert(+x + +y); //数字1+2=3

虽然包含大量加号的表达式看起来非常奇怪,但是,如果熟悉了JavaScript的语法格式,这么做简洁且高效。

上例中可以看到,单目运算符是在双目运算符之前执行的,这是运算符之间优先级引起的,JavaScript引擎总是先计算优先级较高的运算符。

运算符优先级

当一个表达式拥有多个运算符时,执行的顺序则由运算符的优先级决定。

小学我们就知道在表达式1 + 2 * 3中,先做乘除后做加减,这就说明乘除法比加减法优先级更高。

圆括号可以改变运算顺序,在运算符中拥有最高优先级,如果我们对现有的运算顺序不满意,可以用圆括号来修改顺序,例如(1 + 2) * 3就可以让加法在乘法之前计算。

JavaScript有许多运算符,每个运算符都有对应的优先级数字。如果优先级相同,则按照由左至右的顺序执行。

优先级名称符号
15单目加号 +
15单目负号-
14求幂**
13乘号*
13除号/
12加号+
12减号-
2赋值符=

上表可以看出,单目运算符的加减号要高于双目运算符的加减号,这也是为什么在表达式中会先计算单目运算符的原因。

赋值运算符 =

等号=本身也是一个运算符,它的作用就是将等号右边的表达式结果赋值给左边的变量。

这也是为什么等号的优先级比较低的缘故,这样就可以保证所有右侧的计算全部完成后再向左侧赋值。

let result = 1 + 2 ** 3;
alert(result); // 9

或者,直接将一个变量的值赋给另外一个变量:

let x = 666;
let y = x;
alert(y); // 666

同一个表达式中,赋值运算符可以不止一个:

let a = 1;
let b = 2;
let c = a * (a = a + b);
alert(c); // 3
alert(a); // 3

如果我们以结果逆向推算表达式的计算过程,可以发现,引擎依旧是从左向右运算,首先将第一个a替换为1,也就是1 + (a = a + b),然后计算括号内的内容,得到1 + (a = 1 + 2),最后再赋值给c

强调: 绝对不推荐编写代码的时候采用这种方式,不仅容易出错,而且会得罪队友。

链式赋值

赋值运算符也可以在一行中赋值多个变量:

let a, b, c;
a = b = c = 1 + 1;
alert(a); // 2
alert(b); // 2
alert(c); // 2

同样的,为了可读性起见,建议每行只做一次赋值:

a = 1 + 1;
b = a;
c = a;

我们在写代码的时候,炫技虽然是乐趣之一
但是简朴、稳定、可读的代码更是老手的典范
真正的高手往往能够写出小白都能看懂的代码

自增、自减运算符

我们在编程过程中,会经常遇到变量的加一、减一操作,尤其是在循环语句中。

在正常情况下,我们可以通过如下方式实现计算:

let a = 1;
let b = 2;
a = a + 1;
b = b - 1;
alert(a); // 2
alert(b); // 1

JavaScript提供了一种更为简洁高效的做法:

  • 自增运算符 ++
let a = 1;
a++; // 作用和 a = a + 1;相同
alert(a);
  • 自减运算符 --
let b = 9;
b--;    // 作用和 b = b - 1;相同
alert(b);

自增自减运算符还可以放置在变量的前面:

let a = 1;
++a; // 作用和 a = a + 1;相同
alert(a);

let b = 9;
--b;    // 作用和 b = b - 1;相同
alert(b);

前置和后置的 ++/--都会完成变量的自增、自减操作,但是二者的返回值完全不同。

每个运算符都会有一个返回值,自增自减同样如此,前置的自增/减运算符会先执行自增/减计算,然后返回计算后的值,后置的自增/减运算符会先返回变量值本身,然后在进行自增/减运算。

let a = 1;
let b = ++a;
alert(b);   // b = 2

前置的++运算符会先执行自增运算,然后返回自增后的结果,所以b = 2

let a = 1;
let b = a++;
alert(b);   // b = 1;

后置的++运算符会先返回a的值,然后再执行自增运算,所以b = 1

自增/减运算符也可以放在表达式中使用,由于优先级较高,没有必要使用圆括号:

let a = 1;
let b = 2;
let c = a++ + --b;
alert(c);   // 2

虽然,这样写也没有太大问题,但是依旧建议大家将代码写为以下形式:

let a = 1;
let b = 2;
--b;
let c = a + b;
a++;
alert(c);   // 2

位运算符

以上运算符都是站在十进制的基础上,而位运算符则是站在32位二进制的基础上进行的计算,大部分的编程语言都支持这些运算符。
位运算符包括:

  1. &
  2. |
  3. ~
  4. 异或 ^
  5. 左移 <<
  6. 右移 >>
  7. 无符号右移 >>>

为了计算方便,计算机中所有的数据都是以二进制的方式存储再计算机中的,也就是只包含01的数字串。

由于位运算符使用的场景很少,且需要大量的理论知识作为铺垫,所以不在本文细讲,后面会专门出一节详细讲解原码、反码和补码,同时介绍它们与位运算的关系。

运算符简写

由于我们经常需要对同一个变量做运算,同时还要将运算的结果存储在变量中,例如:

let a = 1;
a = a + 1;
a = a - 1;
a = a * 2;
a = a / 2;

可以使用运算符简写 += -= *= /= ,提高编程效率,以上代码完全等价于下面的代码:

let a = 1;
a += 1; // a = a + 1; 
a -= 1; // a = a - 1;
a *= 2; // a = a * 2;
a /= 2; // a = a / 2;

此类简写的运算符优先级和=完全相同,所以会在右侧表达式计算完成之后运行:

let a = 2;
a *= 1 + 1;
alert(a); // 4

逗号运算符

逗号也是一种运算符,只不过大多数人都没有意识到这一点,常用于编写更简短的代码。

逗号运算符可以让我们在同一行执行多个表达式计算,表达式之间用逗号分割,但是只有最后一个表达式会返回结果

举个栗子:

let a = (1 + 2, 3 + 4);

alert( a ); // 7(3 + 4 的结果)

第一个语句1 + 2虽然计算了,但是并不会返回结果,随后计算3 + 4,并返回计算结果。

逗号运算符的优先级非常低,比'='还要低,因此上面你的例子中圆括号非常重要,否则逗号还没有发挥作用a就会被赋值33 + 4的结果会被丢弃。

为什么我们需要这样一个运算符,它只返回最后一个值呢?

有时候,人们会使用它把几个行为放在一行上来进行复杂的运算。

举个例子:

// 一行上有三个运算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

这样的技巧在许多JavaScript框架中都有使用,这也是为什么我们提到它。但是通常它并不能提升代码的可读性,使用它之前,我们要想清楚。

课后作业

  1. 计算程序输出
let a = 1;
let b = 2;
let c = ++a * b--;
alert(c);//?
  1. 补全程序
let r = 2 ___ 3;
alert(r);//如果此处输出8,下划线上应该是什么?
  1. 修改程序
let a = prompt("请输入一个数字?", 8);
let b = prompt("请输入另一个数?", 7);

alert(a*b); // 如果我希望输出56,程序应该怎么改?
  1. 判断输出
let x = '1';
x += +x++ + ++x;
alert(x); //?

章节目录
上一篇:《类型转换》
下一篇:《比较运算符》


  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@魏大大

我们都没有打赏的习惯

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值