重学JavaScript之基本概念(中) => 操作符

注意: 本文章为 《重学js之JavaScript高级程序设计》系列第三章第二部分【操作符】。
关于《重学js之JavaScript高级程序设计》是重新回顾js基础的学习。

1. 操作符

用于描述一组可以操作数据值的概念叫做操作符。包括 算术操作符(加号和减号)、位操作符、关系操作符和相等操作符。ES的操作符和其他不同的在于它能够适用于很多值,如:字符串、数字值、布尔值、甚至对象。在应用于对象的时候,需要调用对象的 valueOf() 和 toString()方法。

1.1 一元操作符

只能操作一个值的操作符叫做一元操作符。

1.1.1 递增和递减操作符

分为两种类型:前置和后置型,前置位于要操作的变量之前。后置则在要操作的变量之后。如下:

var age = 29
++age // 30

等于

age = age + 1

--age // 28

等于

age = age - 1

注意:执行前置递增或递减的时候,变量的值都是在语句被求值以前改变的。

var age = 29
var a = --age + 2

age // 28
a // 30

// 由于前置递增和递减与执行语句的优先级相等,
所以整个语句会被从左到右求值。

var num1 = 2
var num2 = 20
var num3 = --num1 + num2 // 21
var num4 = num1 + ++num3 // 23

后置型递增和递减操作语法不变,只不过由前面放到了后面,而且最重要的是:后置型递增和递减的操作都是在变量执行之后在操作的。如下:

var num = 3
var age = 4

num-- + age-- // 7
num // 2
age // 4

总结:

以上4个操作符对任何值都适用,不限于数字还可以用于字符串、布尔值、浮点数值和对象,规则如下:
1、应用于数字字符的字符串时候,先将其转换为数字值,
在执行加减 1 的操作,字符串变量变成数值变量。

2、应用于不包含有效数字的字符串时,将其变量的值设置
位NaN,字符串变量变成数值变量

3、用于布尔值false的时候,将其转换为0,在执行加减1的
操作,布尔值变成数值

4、用于布尔值true的时候,将其转换为1,在执行加减1的操
作,布尔值变成数值

5、用于浮点数,执行加减1的操作

6、用于对象,先调用对象的valueOf()方法,如果返回的结果
是NaN在调用toString()方法,对象的变量变成数值变量。

上面的说明如下:

var s1 = '2'
var s2 = 'z'
var s3 = false
var s4 = 1.1
var s5 = {
    valueOf: function(){
        return -1
    }
}

s1++ // 3
s2++ // NaN
s3++ // 1
s4-- // 0.10000000000009
s5-- // -2

1.1.2 一元加和减操作符

一元加操作符放在变量之前是没有任何变化的,而一元减操作符放在变量之前则变量是个负数

var num = 25
num = +num // 25

num = -num // -25

注意:还是遵循之前的规则,对于字符串的变量使用加减操作符 则变成 NaN 其他的则相应变成指定规则的数值。

一元加减操作符主要用于基本的算术运算,也可以用于转换数据类型。

1.2 位操作符

位操作符是用于内存中表示数值的位来操作数值。ES中所有的值都是按照64位格式存储,但位操作符并直接操作64位值,而是先将64位的值转换成32位整数,然后执行操作,最后在将结果转换位64位。

对于有符号的整数,32位中的前31位用于表示整数的值,第32位表示数值的符号,0表示整数,1表示负数。这个表示符号的位叫做符号位。符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂,第一位表示 2的0次方以此类推。没有用到的用0填充忽略不计。也就是2进制表示法。

负数同样可以以二进制存储,但是使用的格式是二进制补码,计算一个数值的二进制补码步骤如下:

1、求这个数值绝对值的二进制码
2、求二进制反码
3、得到的二进制反码 +1

如下:求 -18的二进制码
0000 0000 0000 0000 0000 0001 0010
求反码 0 1 互换
1111 1111 1111 1111 1111 1110 1101
然后 加 1 
1111 1111 1111 1111 1111 1110 1110

在ES中,ES会尽力向我们隐藏所有这些信息,也就是说,在二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码之前加了一个负号,如下:

var num = -18
num.toString(2) // '-10010'

注意:默认情况下,ES中所有的整数都是有符号整数,当然也存在无符号整数,对于无符号整数来说,第32位不再表示符号,因为无符号整数只能是正数,而且无符号整数的值可以更大,因为多出来的一位不再表示符号,可以用来表示数值。

在ES中当对应数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成32位数值,然后执行位操作,最后再将32位数值转换回64位数值。这样表面上看起来好像是在操作 32 位数值,另外有个问题,这样的操作导致在特殊值 如 NaN 和 Infinity值应用位操作的时候,这两个值会被当成0来处理。

注意:如果对非数值进行位操作符,那么会先使用 Number() 函数将该值转换为一个数值,在应用位操作,得到的结果是一个数值。

  1. 按位非(NOT)

按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码并减一,如下:

var num = 25    // 二进制 0001 1001
var num1 = ~num // 二进制 1110 0110

// -26
  1. 按位与

按位与操作符由一个和字符号(&)表示,它有两个操作符数。从本质上来讲,按位与操作就是将两个数值的每一位对齐,根据以下规则,对相同位置上的两个数执行AND操作:

结果:全1才为1,有0返回0

第一个数值的位 第二个数值的位 结果
1 1 1
1 0 0
0 1 0
0 0 0
  1. 按位或(OR)

按位或由一个竖线符号(|)表示,同样也有两个操作数,操作结果遵循下表。

第一个数值的位 第二个数值的位 结果
1 1 1
1 0 1
0 1 1
0 0 0

结果:有1返回1,全0返回0

  1. 按位异或(XOR)

按位异或操作符由一个插入符号 (^)表示,也是两个操作数,结果遵循下表:

第一个数值的位 第二个数值的位 结果
1 1 0
1 0 1
0 1 1
0 0 0

结果:两个数只有1个为1的时候才返回1,同时为1或同时为0 则返回0

  1. 左移

左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。如下:

// 将数值2向左移动5位,结果就是64位

var oldnum = 2  // 二进制 10 
var newnum = oldnum << 5  // 二进制 1000000 , 十进制 64

注意: 在向左移位后,原数值的右侧多出了 5 个空位,左移操作
会以0来填充这些空位,以便得到的结果是一个完整的32位的二进制数。
  1. 有符号的右移

有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记),有符号的右移操作与左移操作恰好相反,即如果将64向右移动5位,结果将变回2.如下:

var oldnum = 64 // 二进制 1000000
var newnum = oldnum >> 5    // 二进制 10 2

注意:在移位的过程中,原数值也会出现空位,只不过这次
空位出现在原数值的左侧、符号位的右侧,这时候ES就会用
符号位的值来填充所有的空位,以便得到一个完整的值。
  1. 无符号右移

无符号右移操作符右三个大于号(>>>)组成,这个操作符会将数值的所有32位都向右移动,对于正数来说,无符号右移的结果与有符号右移相同,如下

var oldnum = 64     // 二进制 1000000
var newnum = oldnum >>> 5   // 二进制 10  十进制 2

注意:在负数下情况就不一样了,首先,无符号右移是以0来填充空位,而不是像有符号右移那样以符号位来填充空位。所以,对正数的无符号右移与有符号右移结果相同,但对负数的结果就不一样了。其次无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值补码形式表示,因此就会导致无符号右移后的结果非常之大。如下:

var oldnum = -64    // 二进制 11111111111111111111111111000000
var newnum = oldnum >>> 5   // 十进制 134217726

欢迎关注 公众号【小夭同学】

重学js系列

重学js之JavaScript简介

重学 JS 之在 HTML 中使用 JavaScript

重学js之JavaScript基本概念(上)=> 数据类型

ES6入门系列

ES6入门之let、cont

ES6入门之变量的解构赋值

ES6入门之字符串的扩展

ES6入门之正则的扩展

ES6入门之数值的扩展

ES6入门之函数的扩展

ES6入门之数组的扩展

ES6入门之对象的扩展

Git教程

前端Git基础教程