JavaScript浅析 -- 运算符和优先级

一、运算符

JavaScript中的运算符,主要用于连接简单表达式,组成一个复杂的表达式。在运算过程中,会根据需要将操作数转换成特定的类型进行运算,最后输出指定的类型。我个人习惯将他分为6大类进行记忆:算术运算符,比较运算符,布尔运算符,赋值运算符,位运算符,其他运算符。

(一)算术运算符(10个)
  • 加法运算符(Addition):x + y
  • 减法运算符(Subtraction): x - y
  • 乘法运算符(Multiplication): x * y
  • 除法运算符(Division):x / y
  • 余数运算符(Remainder):x % y
  • 自增运算符(Increment):++x 或者 x++
  • 自减运算符(Decrement):--x 或者 x--
  • 求负运算符(Negate):-x
  • 数值运算符(Convert to number): +x
  • 指数运算符 (Exponential operator) : x**y ,如2**4=16

说明:
(1) x++先参与运算然后x再做加一操作。如console.log(2 - a++)相当于console.log(2-a); a = a+1;++x先进行加一操作再参与运算。如console.log(2 - ++a)相当于a=a+1;console.log(2-a)
(2) 取余的正负号取决于第一位数,如-7%2为-1;7%-2为1,所以为了得到负数的正确余值需要用绝对函数,如判断num是否为偶数时Math.abs(num) % 2
(3) +x一般用来做转数的操作,如+new Date()、+[] // 0、+{} // NaN、+true // 1,其实相当于Number(x)只是结果为正。
(4) +号运算时才确定是相加还是连接,如果有一方是字符串则变成连接符。对于对象相加先调用valueOf()再调用toString(),但是valueOf()返回的一般是原对象,所以一般都会调用toString()。特例,Date对象反着来,先toString()再valueOf()。如'3' + 5 + 6 // 3563 + 5 + '6' // ‘86’

(二)比较运算符(8个)
  • == :相等
  • === :严格相等
  • != :不相等
  • !== :严格不相等
  • < :小于
  • <= :小于或等于
  • > :大于
  • >= :大于或等于

说明:
===是严格等于,要求类型和数值都相等(其中NaN===NaN为false);而==会进行隐式转换之后再比较值是否相等。具体的转换规则参考文章。

(三)布尔运算符(4个)
  • ! :取反运算符
  • && :且运算符
  • || :或运算符
  • condition? true case : false case :三元条件运算符

说明:
(1) !a会对a先做Boolean()转换操作,然后对转换的布尔值进行取反,如!0为!Boolean(0)结果为true。
(2) 且和或的运算均为短路运算,即a && b两个为true才为true,a为false则不再管b;a || b一个为true则为true,a为true则不再管b。
(3) condition ? a : b相当于if(condition) { a } else { b }

(四)位运算符(7个)
  • 或运算(or):符号为|,表示两个二进制位中有一个为1,则结果为1,否则为0。
  • 与运算(and):符号为&,表示两个二进制位都为1,则结果为1,否则为0。
  • 否运算(not):符号为~,表示将一个二进制位变成相反值。
  • 异或运算(xor):符号为ˆ,表示两个二进制位中有且仅有一个为1时,结果为1,否则为0。
  • 左移运算(left shift):符号为<<
  • 右移运算(right shift):符号为>>
  • 带符号位的右移运算(zero filled right shift):符号为>>>
(五)赋值运算符(11个)
  • 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
  • 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
(六)其他运算符
  • 小括号:有两种用法,如果把表达式放在圆括号之中,作用是求值;如果跟在函数的后面,作用是调用函数。
  • void:void运算符的作用是执行一个表达式,然后返回undefined。常见的a标签写上javascript:void(0)就是这个原理,会运行冒号后面的表达式但返回undefined就没执行。
  • 逗号运算符:逗号运算符用于对两个表达式求值,并返回后一个表达式的值。
  • typeof运算符:返回操作数的类型,其中typeof null结果'object',typeof Function结果是'function'。
  • instanceof运算符:a instanceof b判断a是否是b的实例,返回布尔值。

二、运算符的优先级

运算符的优先级顺序如下(上大于下,左大于右)
++、--(右结合大于左结合)、-(转负数)、+(转数)、~(位反)、!(取反)
delete、typeof、void
*、/、%、+、-
<=、>=、==、!=、===、!==
||、&&、?:、赋值、,

说明:
(1) 优先级指的是同时出现的时候先计算高优先级部分,而不是说先当做这个。例如转数的加号优先级高于加法的加号,1+'3‘++new Date()不是说把加号先当做转数符,如果是那么1+'3'结果是4但结果是'13‘,很显然是作为加号使用。而是说先计算+new Date()得到时间戳1531139346042,再执行1+'3‘+1531139346042
(2) ++、--之类的操作数必须是可以放在赋值左边的数而不能是常数,比如4++会报错。还有下面的例子也要注意:

var a=0, b=0;
a+++b; // 0
a; // 1
b; // 0

右结合的优先级高于左结合和加号,上面会先找有没有右结合,找到a++先运算,所以运算顺序是(a++)+b
(3) typeof的优先级比加减乘除还高,所以一般习惯把操作数加上括号,如

typeof 2*3; // NaN
typeof (2*3); // 'number'
typeof 2+3; // 'number3'

(4) 逻辑非优先级高于加减乘除,但逻辑或和逻辑与比加减乘除优先级低。!2*0相当于(!2)*0
(5) 逻辑或||、逻辑与&&的短路运算要注意,且返回的是其中的一个表达式,而不是布尔值。1 && "hi" || 0的结果是'hi'
(6) 赋值的优先级非常低。

a = b == c // 相当于a = (b==c)

下面这个例子,先自己猜一下结果,再看正确答案。arr.length会报错吗?

var arr, arr2;
arr2 = arr = [1, 2, 3];
arr[arr.length] = arr = 4;
console.log(arr);
console.log(arr2);

上面这个,由于赋值的优先级非常低最后才执行,arr[arr.length] = arr = 4其实是先算的arr[arr.length]是指向arr[3]的一个地址(和arr2[3]指向的是同一个),接着4赋值给arr然后arr的值4赋值给这块地址指向的内存(也就是arr2[3]变成了4)。所以结果是arr为4,arr2为[1, 2, 3, 4]。
再来看个例子也是类似。

var a = {n: 1};
var b = a;
a.x = a = {n:2};
console.log(a.x); // undefined
console.log(b.x); // {n: 2}

你可能感兴趣的:(JavaScript浅析 -- 运算符和优先级)