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 相关文章推荐
[对联广告] JS脚本类
Aug 27 Javascript
Javascript实现的分页函数
Feb 07 Javascript
jQuery 过滤方法filter()选择具有特殊属性的元素
Jun 15 Javascript
window.print打印指定div指定网页指定区域的方法
Aug 04 Javascript
jQuery mobile类库使用时加载导航历史的方法简介
Dec 04 Javascript
JavaScript SHA512加密算法详细代码
Oct 06 Javascript
jQuery实现表格与ckeckbox的全选与单选功能
Nov 24 Javascript
vue组件间通信解析
Mar 01 Javascript
收集前端面试题之url、href、src
Mar 22 Javascript
vue请求数据的三种方式
Mar 04 Javascript
用云开发Cloudbase实现小程序多图片内容安全监测的代码详解
Jun 07 Javascript
Vue 电商后台管理项目阶段性总结(推荐)
Aug 22 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作的文本留言本的例子(一)
2006/10/09 PHP
用PHP的ob_start() 控制您的浏览器cache
2009/08/03 PHP
探讨php中header的用法详解
2013/06/07 PHP
php获取数组长度的方法(有实例)
2013/10/27 PHP
文本加密解密
2006/06/23 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
2012/12/27 Javascript
用jquery模仿的a的title属性(兼容ie6/7)
2013/01/21 Javascript
javascript 对象数组根据对象object key的值排序
2015/03/09 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
2015/03/13 Javascript
jQuery+CSS3折叠卡片式下拉列表框实现效果
2015/11/02 Javascript
使用JQuery实现的分页插件分享
2015/11/05 Javascript
JQuery实现的按钮倒计时效果
2015/12/23 Javascript
JQuery解析XML的方法小结
2016/04/02 Javascript
仅一个form表单 js实现注册信息依次填写提交功能
2016/06/12 Javascript
JavaScript兼容性总结之获取非行间样式案例
2016/08/07 Javascript
AngularJS中$apply方法和$watch方法用法总结
2016/12/13 Javascript
js事件冒泡与事件捕获详解
2017/02/20 Javascript
Vue使用Canvas绘制图片、矩形、线条、文字,下载图片
2019/04/26 Javascript
15 分钟掌握vue-next响应式原理
2019/10/13 Javascript
Vue 实现点击空白处隐藏某节点的三种方式(指令、普通、遮罩)
2019/10/23 Javascript
Vue路由 重定向和别名的区别说明
2020/09/09 Javascript
python实现html转ubb代码(html2ubb)
2014/07/03 Python
Python编写检测数据库SA用户的方法
2014/07/11 Python
python协程用法实例分析
2015/06/04 Python
读写json中文ASCII乱码问题的解决方法
2016/11/05 Python
搞定这套Python爬虫面试题(面试会so easy)
2019/04/03 Python
简单了解python gevent 协程使用及作用
2019/07/22 Python
python框架flask表单实现详解
2019/11/04 Python
Python 合并拼接字符串的方法
2020/07/28 Python
Python常用base64 md5 aes des crc32加密解密方法汇总
2020/11/06 Python
html5使用canvas绘制太阳系效果
2014/12/15 HTML / CSS
丝芙兰墨西哥官网:Sephora墨西哥
2020/05/30 全球购物
大四学生思想汇报
2014/01/13 职场文书
北京大学自荐信范文
2014/01/28 职场文书
党的群众路线教育实践活动个人对照检查材料(四风)
2014/11/05 职场文书
MySQL系列之十四 MySQL的高可用实现
2021/07/02 MySQL