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 相关文章推荐
JavaScript 获得选中文本内容的方法
Feb 15 Javascript
回车直接实现点击某按钮的效果即触发单击事件
Feb 27 Javascript
JavaScript模拟深蓝vs卡斯帕罗夫的国际象棋对局示例
Apr 22 Javascript
javascript实现input file上传图片预览效果
Dec 31 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
Aug 11 Javascript
vue element中axios下载文件(后端Python)
May 10 Javascript
JS实现移动端点击按钮复制文本内容
Jul 28 Javascript
解决layui轮播图有数据不显示的情况
Sep 16 Javascript
vue ajax 拦截原理与实现方法示例
Nov 29 Javascript
JS精确判断数据类型代码实例
Dec 18 Javascript
es6数组的flat(),flatMap()函数用法实例分析
Apr 18 Javascript
Vue.extend 登录注册模态框的实现
Dec 29 Vue.js
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简单开启gzip压缩方法(zlib.output_compression)
2013/04/13 PHP
php实现zip压缩文件解压缩代码分享(简单易懂)
2014/05/10 PHP
9个经典的PHP代码片段分享
2014/12/18 PHP
session 加入redis的实现代码
2016/07/15 PHP
jquery 之 $().hover(func1, funct2)使用方法
2012/06/14 Javascript
使用jquery实现放大镜效果
2014/09/02 Javascript
Javascript基础教程之break和continue语句
2015/01/18 Javascript
jQuery使用toggleClass方法动态添加删除Class样式的方法
2015/03/26 Javascript
JavaScript实现基于十进制的四舍五入实例
2015/07/17 Javascript
JS基于封装函数实现的表格分页完整示例
2018/06/26 Javascript
JS+HTML5实现获取手机验证码倒计时按钮
2018/08/08 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
详解webpack编译速度提升之DllPlugin
2019/02/05 Javascript
vue 实现路由跳转时更改页面title
2019/11/05 Javascript
Vue-cli打包后部署到子目录下的路径问题说明
2020/09/02 Javascript
你不知道的SpringBoot与Vue部署解决方案
2020/11/09 Javascript
几个提升Python运行效率的方法之间的对比
2015/04/03 Python
django使用html模板减少代码代码解析
2017/12/12 Python
pandas去除重复列的实现方法
2019/01/29 Python
python读写csv文件方法详细总结
2019/07/05 Python
Python 字符串类型列表转换成真正列表类型过程解析
2019/08/26 Python
在notepad++中实现直接运行python代码
2019/12/18 Python
python绘制玫瑰的实现代码
2020/03/02 Python
Python多线程操作之互斥锁、递归锁、信号量、事件实例详解
2020/03/24 Python
超级实用的8个Python列表技巧
2020/08/24 Python
python 将Excel转Word的示例
2021/03/02 Python
Too Faced官网:美国知名彩妆品牌
2017/03/07 全球购物
煤矿班组长岗位职责
2013/12/29 职场文书
一位农村小子的自荐信
2014/04/07 职场文书
应届大专生求职信
2014/06/26 职场文书
2014年村支部书记四风对照检查材料思想汇报
2014/10/02 职场文书
民间借贷纠纷答辩状
2015/08/03 职场文书
2016年万圣节活动总结
2016/04/05 职场文书
css3中2D转换之有趣的transform形变效果
2022/02/24 HTML / CSS
Flutter集成高德地图并添加自定义Maker的实践
2022/04/07 Java/Android
vue中this.$http.post()跨域和请求参数丢失的解决
2022/04/08 Vue.js