javascript运算符——位运算符全面介绍


Posted in Javascript onJuly 14, 2016

前面的话

位运算符是非常底层的运算,由于其很不直观,所以并不常用。但是,其速度极快,且合理使用能达到很好的效果。本文将介绍javascript中常常被忽视的运算符——位运算符

二进制表示  

ECMAScript中的所有数值都以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值,而是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数

这种位数转换使得在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理

如果对非数值应用位操作符,会先使用Number()将该值转换成数值再应用位操作,得到的结果是一个数值

//'|'表示按位或,一个整数与0按位或运算可以得到它本身,一个小数与0按位或运算可以得到取整效果
console.log( 1.3 | 0);//1
console.log( 1.8 | 0);//1
console.log( Infinity | 0);//0
console.log( -Infinity | 0);//0
console.log( NaN | 0);//0
console.log('12px' | 0);//0
console.log('12' | 0);//12

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

例如,数值18的二进制表示是00000000000000000000000000010010,或者更简洁的10010。这是5个有效位,这5位本身就决定了实际的值

javascript运算符——位运算符全面介绍

console.log((18).toString(2));//"10010"

console.log(0b00000000000000000000000000010010);//18

javascript运算符——位运算符全面介绍

负数同样以二进制存储,但使用的格式是二进制补码。计算一个数值的二进制补码,需要经过下列3个步骤:

【1】求这个数值绝对值的二进制码

【2】求二进制反码,即将0替换成1,将1替换成0

【3】得到的二进制反码加1

例如,要确定-18的二进制表示,首先必须得到18的二进制表示,如下所示:

0000 0000 0000 0000 0000 0000 0001 0010

接下来,计算二进制反码,如下所示:

1111 1111 1111 1111 1111 1111 1110 1101

最后,在二进制反码上加 1,如下所示:

1111 1111 1111 1111 1111 1111 1110 1101
                   1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110

因此,-18 的二进制表示即 1111 1111 1111 1111 1111 1111 1110 1110

ECMAScript会尽力向我们隐藏所有这些信息,在以二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码前面加上了一个负号

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

位运算符可以进行7种运算,包括按位非(NOT)、按位与(AND)、按位或(OR)、按位异或(XOR)、左移、有符号右移和无符号右移

按位非(NOT)  

按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。其本质是操作数的负值减1

var num1 = 25;
var num2 = ~num1;
console.log(num2);//-26

对一个整数两次按位非,可以得到它本身;对一个小数两次按位非,可以得到取整效果

console.log(~~3);//3
console.log(~~3.1);//3
console.log(~~3.9);//3

按位与(AND)

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

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

按位与操作只有在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0

var iResult = 25 & 3;
console.log(iResult);//"1"
//分析如下
 25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0001

按位或(OR)

按位或操作符由一个竖线符号(|)表示,同样也有两个操作数,按位或操作遵循下面这个真值表

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

按位或操作在有一个位是1的情况下就返回1,而只有在两个位都是0的情况下才返回0

var iResult = 25 | 3;
console.log(iResult);//"27"
//分析如下
25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
--------------------------------------------
OR = 0000 0000 0000 0000 0000 0000 0001 1011

一个整数与0按位或运算可以得到它本身,一个小数与0按位或运算可以得到取整效果

console.log(3.1 | 0);//3
console.log(3.9 | 0);//3

按位异或(XOR)

按位异或操作符由一个插入符号(^)表示,也有两个操作数。以下是按位异或的真值表

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

按位异或的两个数值相同时返回0,不同时返回1

var iResult = 25 ^ 3;
console.log(iResult);//"26"
//分析如下
 25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
XOR = 0000 0000 0000 0000 0000 0000 0001 1010

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

var a=10,b=9;
a ^= b, b ^= a, a ^= b;
console.log(a,b);//9,10
//分析如下
 a = 0000 0000 0000 0000 0000 0000 0000 1010
 b = 0000 0000 0000 0000 0000 0000 0000 1001
---------------------------------------------
 a1 = 0000 0000 0000 0000 0000 0000 0000 0011

 a1 = 0000 0000 0000 0000 0000 0000 0000 0011 
 b = 0000 0000 0000 0000 0000 0000 0000 1001
---------------------------------------------
 b1 = 0000 0000 0000 0000 0000 0000 0000 1010
 
 b1 = 0000 0000 0000 0000 0000 0000 0000 1010 
 a1 = 0000 0000 0000 0000 0000 0000 0000 0011 
---------------------------------------------
 a2 = 0000 0000 0000 0000 0000 0000 0000 1001
//a=a2=10;b=b1=9

一个整数与0按位异或可以保持其自身,一个小数与0按位异或可以取整

console.log(3.1 ^ 0);//3
console.log(3.9 ^ 0);//3

左移

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

例如,如果将数值2(二进制码为10)向左移动5位,结果就是64(1000000)

javascript运算符——位运算符全面介绍
var oldValue = 2;
var newValue = oldValue<<5;
console.log(newValue);//64

左移不会影响操作数的符号位。换句话说,如果将-2向左移动5位,结果将是-64

var oldValue = -2;
var newValue = oldValue<<5;
console.log(newValue);//-64

左移0位可以实现取整效果

console.log(3.1 << 0);//3
console.log(3.9 << 0);//3

有符号右移

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

var oldValue = 64;
var newValue = oldValue>>5;
console.log(newValue);//2

同样,在移位过程中,原数值中也会出现空位。只不过这次的空位出现在原数值的左侧、符号位的右侧。而此时ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值

右移可以模拟2的整除运算

console.log(5>>1);//2
console.log(15>>1);//7

无符号右移

无符号右移操作符由3个大于号(>>>)表示,这个操作符会将数值的所有32位都向右移动。对正数来说,无符号右移的结果与有符号右移相同。仍以前面有符号右移为便,如果将64无符号右移5位,结果仍然是2

var oldValue = 64;
var newValue = oldValue>>>5;
console.log(newValue);//2

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

var oldValue = -64;
var newValue = oldValue>>>5;
console.log(newValue)//134217726

要确定-64的二进制表示,首先必须得到64的二进制表示,如下所示:

0000 0000 0000 0000 0000 0000 0100 0000

接下来,计算二进制反码,如下所示:

1111 1111 1111 1111 1111 1111 1011 1111

最后,在二进制反码上加 1,如下所示

1111 1111 1111 1111 1111 1111 1011 1111
                   1
---------------------------------------
1111 1111 1111 1111 1111 1111 1100 0000

向右移动5位后,如下所示:

0000 0111 1111 1111 1111 1111 1111 1110

console.log(0b00000111111111111111111111111110);//134217726

常见应用

【1】乘法运算

利用左移(<<)来实现乘法运算

console.log(2 << 1);//4
console.log(3 << 1);//6
console.log(4 << 1);//8

【2】除法运算

利用有符号右移(>>)来模拟2的整除运算

console.log(2 >> 1);//1
console.log(5 >> 1);//2
console.log(8 >> 1);//4
console.log(9 >> 1);//4

【3】值互换

利用异或操作(^)可以实现值互换的效果

var a=10,b=9;
a ^= b, b ^= a, a ^= b;
console.log(a,b);//9,10

【4】小数取整

利用取两次按位非、与0按位或、与0按位异或、左移0位、右移0位都可以实现小数取整效果

console.log(~~3.1);//3
console.log(3.1|0);//3
console.log(3.1^0);//3
console.log(3.1<<0);//3
console.log(3.1>>0);//3

【5】开关

位运算符可以用作设置对象属性的开关。假定某个对象有四个开关,每个开关都是一个变量。那么,可以设置一个四位的二进制数,它的每个位对应一个开关

var FLAG_A = 1; // 0001
var FLAG_B = 2; // 0010
var FLAG_C = 4; // 0100
var FLAG_D = 8; // 1000

上面代码设置A、B、C、D四个开关,每个开关分别占有一个二进制位

现在假设需要打开ABD三个开关,我们可以构造一个掩码变量

var mask = FLAG_A | FLAG_B | FLAG_D;
// 0001 | 0010 | 1000 => 1011

上面代码对ABD三个变量进行“或运算”,得到掩码值为二进制的1011

//“或运算”可以确保打开指定的开关
flags = flags | mask;
//“与运算”可以将当前设置中凡是与开关设置不一样的项,全部关闭
flags = flags & mask;
//“异或运算”可以切换(toggle)当前设置,即第一次执行可以得到当前设置的相反值,再执行一次又得到原来的值
flags = flags ^ mask;
//“否运算”可以翻转当前设置,即原设置为0,运算后变为1;原设置为1,运算后变为0
flags = ~flags;

以上这篇javascript运算符——位运算符全面介绍就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Prototype使用指南之dom.js
Jan 10 Javascript
JQuery 选择和过滤方法代码总结
Nov 19 Javascript
JQuery判断checkbox是否选中及其它复选框操作方法合集
Jun 01 Javascript
跟我学习javascript的this关键字
May 28 Javascript
JS模拟简易滚动条效果代码(附demo源码)
Apr 05 Javascript
jQuery实现表格与ckeckbox的全选与单选功能
Nov 24 Javascript
javaScript语法总结
Nov 25 Javascript
JavaScript中如何判断一个值的类型
Sep 15 Javascript
用ES6的class模仿Vue写一个双向绑定的示例代码
Apr 20 Javascript
微信小程序实现原生步骤条
Jul 25 Javascript
详解package.json版本号规则
Aug 01 Javascript
原生JS实现pc端轮播图效果
Dec 21 Javascript
Angular.js 实现数字转换汉字实例代码
Jul 14 #Javascript
JavaScript——DOM操作——Window.document对象详解
Jul 14 #Javascript
window.close(); 关闭浏览器窗口js代码的总结介绍
Jul 14 #Javascript
Jquery实现遮罩层的简单实例(就是弹出DIV周围都灰色不能操作)
Jul 14 #Javascript
jQuery实现公告新闻自动滚屏效果实例代码
Jul 14 #Javascript
jQuery mobile在页面加载时添加加载中效果 document.ready 和window.onload执行顺序比较
Jul 14 #Javascript
javascript运算符语法全面概述
Jul 14 #Javascript
You might like
如何利用php+mysql保存和输出文件
2006/10/09 PHP
全面解读PHP的Yii框架中的日志功能
2016/03/17 PHP
PHP使用PDO 连接与连接管理操作实例分析
2020/04/21 PHP
解决PHP Opcache 缓存刷新、代码重载出现无法更新代码的问题
2020/08/24 PHP
jQuery 使用个人心得
2009/02/26 Javascript
一个简单的JavaScript数据缓存系统实现代码
2010/10/24 Javascript
通过Jscript中@cc_on 语句识别IE浏览器及版本的代码
2011/05/07 Javascript
Jsonp 跨域的原理以及Jquery的解决方案
2011/06/27 Javascript
jQuery模仿单选按钮选中效果
2016/06/24 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
2016/12/20 Javascript
Angular.js中控制器之间的传值详解
2017/04/24 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
关于jQuery里prev()的简单操作代码
2017/10/27 jQuery
详解angularjs 学习之 scope作用域
2018/01/15 Javascript
Vue动态生成el-checkbox点击无法赋值的解决方法
2019/02/21 Javascript
重置Redux的状态数据的方法实现
2019/11/18 Javascript
[03:15]2014DOTA2国际邀请赛 专访国士无双信心满满
2014/07/12 DOTA
Python简单调用MySQL存储过程并获得返回值的方法
2015/07/20 Python
使用Django Form解决表单数据无法动态刷新的两种方法
2017/07/14 Python
对python抓取需要登录网站数据的方法详解
2018/05/21 Python
Python中修改字符串的四种方法
2018/11/02 Python
Python缓存技术实现过程详解
2019/09/25 Python
Django用户登录与注册系统的实现示例
2020/06/03 Python
python判断变量是否为列表的方法
2020/09/17 Python
python如何编写类似nmap的扫描工具
2020/11/06 Python
Zavvi荷兰:英国大型音像制品和图书游戏零售商
2018/03/22 全球购物
意大利拉斐尔时尚购物网:Raffaello Network(支持中文)
2018/11/09 全球购物
艺术爱好者的自我评价分享
2013/10/08 职场文书
县优秀教师事迹材料
2014/01/31 职场文书
消防应急演练方案
2014/02/12 职场文书
励志演讲稿范文
2014/04/29 职场文书
爱国主义演讲稿
2014/05/07 职场文书
社会体育专业大学生职业生涯规划书
2014/09/17 职场文书
销售督导岗位职责
2015/04/10 职场文书
css3带你实现3D转换效果
2022/02/24 HTML / CSS
Go中使用gjson来操作JSON数据的实现
2022/08/14 Golang