Javascript中的 “&” 和 “|” 详解

一、前言:

在文章开始之前,先出几个题目给大家看看:

var num1 = 1 & 0;
console.log(num1); // 0
var num2 = 'string' & 1;
console.log(num2); // 0
var num3 = true & 1;
console.log(num3); // 1
var num4 = undefined | false;
console.log(num4); // 0
var num5 = undefined | true;
console.log(num5); // 1
var num6 = 23 & 5;
console.log(num6); // 5
var num7 = 23 | 5;
console.log(num7); // 23

上面的题目大家都做对了吗?我们之前有总结过 《浅谈javascript中的 “ && ” 和 “ || ” 》,"&&” 和 “||” 是逻辑运算表达式中的操作符。那么一个 “&” 或者一个 “|” 又代表什么含义呢?有什么特性呢?接下来,我们就来一一揭秘。

首先,我们得清楚 “&” 和 “|” 是位运算操作符。

位运算符用于在最基本的层次上,即按内存中表示数值的位来操作数值。ECMAScript中的所有数值都以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换成32位的整数,然后执行操作,最后再将结果转换为64位。对于开发人员来说,由于64位存储格式是透明的,因此整个过程就像是只存在32位的整数一样。

对于有符号的整数,32位中的前31位用于表示整数的值。第32位表示数值的符号:0表示正数,1表示负数。这个表示符号的位叫做符号位,符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂。第一位(叫做位0)表示20,第二位表示21,以此类推。没有用到的位以0表示,即忽略不计。例如,数值18的二进制表示是0000 0000 0000 0000 0000 0000 0001 0010,或者更简洁的10010。这是5个有效位,这5位本身就决定了实际的值。

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

(1)求这个数值绝对值的二进制码(例如,要求-18的二进制补码,先求18的二进制码);

(2)求二进制反码,即将0替换为1,将1替换为0;

(3)得到的二进制反码加1。

这样,求得了-18的二进制表示,即1111 1111 1111 1111 1111 1111 1110 1110。

......在ECMAScript中,当对数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成32位数值,然后执行位操作,最后再将32位的结果转换回64位数值。这样,表面上看起来就好像是在操作32位数值,就跟在其他语言中以类似方式执行二进制操作一样。但这个转换过程也导致了一个严重的副效应,即在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。

如果对非数值应用位操作符,会先使用Number()函数将该值转换为一个数值(自动完成),然后再应用位操作。得到的结果将是一个数值。 ......(截取自《Javascript高级程序设计》)

二、“&”(按位与AND):

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

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

前面已经把理论性的东西说的太多了,但是我觉得理论又很有必要。接下来,直接分析例子吧!

我们先看上面题目中的 num1,num2,num3以及num6。我们尝试结合上面的理论来分析为什么会输出最终的结果。

// num1是1和0进行“按位与”操作后的返回值。1的二进制码简写为1,0的二进制码简写为0,根据上面的规则,第二个操作符数为0,结果是0
var num1 = 1 & 0;
console.log(num1); // 0
// 第一个操作符数是字符串,按照前言里面的理论,对于非数值的操作符数,先使用Number()函数处理,结果返回NaN,NaN又会被当成0来处理。所以最终结果也是0
var num2 = 'string' & 1;
console.log(num2); // 0
// true是布尔类型值,同样使用Number()函数处理,处理后得到数值1,于是表达式就相当于“1 & 1” 进行位运算,当两个数值都为1的时候,结果返回1
var num3 = true & 1;
console.log(num3); // 1
// 23的二进制码是:...10111,5的二进制码是:...00101。然后每一位进行对齐处理,结合上面的规则,可以得出10111&00101的结果是:00101。00101就是5
var num6 = 23 & 5;
console.log(num6); // 5
// 再加个例子:24的二进制码为...11000,7的二进制码为...00111,相同位置的两个数执行AND操作,结果发现结果是...00000。所以最终结果是0,你算对了吗?
var add1 = 24 & 7;
console.log(add1); // 0 

三、“|”(按位或OR):

按位或操作符由一个竖线符号(|)表示,同样有两个操作符数。从本质上来讲,按位或操作也是将两个数值的每一位对齐,对相同位置上的两个数执行OR操作。

按位或OR操作规则:只要两个数值的对应位有一个是1就返回1,而只有在两个位都是0的情况下才返回0。

我们接最上面的例子来看吧!

// 第一个操作符数为undefined,第二个操作符数是false,均不是数值,所以都要先使用Number()函数处理,处理结果都是返回NaN,NaN又会被当成0处理,于是最终结果是0
var num4 = undefined | false;
console.log(num4); // 0
// 第一个操作符数相当于0,第二个操作符数相当于1,结合按位或的规则,最终结果是1
var num5 = undefined | true;
console.log(num5); // 1
// 23的二进制码是:...10111,5的二进制码是:...00101。然后每一位进行对齐处理,结合上面的规则,可以得出10111|00101的结果是:10111。10111就是23
var num7 = 23 | 5;
console.log(num7); // 23
// 再加个例子:24的二进制码为...11000,7的二进制码为...00111,相同位置的两个数执行AND操作,结果发现结果是...11111。所以最终结果是31,你算对了吗?
var add2 = 24 | 7;
console.log(add2); // 31

四、其他:

相信也会有一些朋友不知道怎么把数值转换成标准的二进制码,那么有没有快速的方法呢?答案是肯定的。

我的网上随机找到了一个在线转换工具地址:数值进制转换(点我查看)。(当然,你也可以使用你找到的别的工具,不管怎样,能实现效果就是我们的最终目的)

最后,再附上我通过手写转换二进制过程中总结的规律图,依然可以快速将数值转换成二进制码,逼格满满哒!

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • Javascript基础回顾之(三) js面向对象

    本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者那里的一知半解,所以决定先花一些时间整理一下这些基础知识和大家分享. 后面会附上培训用的PPT.刚开始是打算写一篇的,但是后来写着写着就发现越来越多,所以决定还是写一个系列吧.本系列所有内容都是涉及Javascript基础的,没有时髦的玩意儿,但是我相信这些基础的东西会有助于你理解那些有趣的东西的.

  • JavaScript基础之AJAX简单的小demo

    AJAX AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下. function prepareForms() { for(var j=0 ; j<document.forms.length ; j++){ var this_forms = document.forms[j]; rese

  • 浅谈javascript中的 “ && ” 和 “ || ”

    有时候,我们会在jQuery框架或者其他js插件中发现里面有很多 " && " 和 " || ",那么这两个标识到底是什么含义?怎么使用?我觉得还是有必要稍微深究一下. 一.原理: && 操作符特点:逻辑运算表达式中只要一个是false就取false的值,都是true取后面,都是false取前面. || 操作符特点:逻辑运算表达式中只要一个是true就取true的值,都是true取前面,都是false取后面. 在js逻辑运算中,我们知

  • JavaScript Date 知识浅析

    Date函数 new Date() Date 对象会自动把当前日期和时间保存为其初始值. date.getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31). date.getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6).周日是0. date.getMonth() 从 Date 对象返回月份 (0 ~ 11). date.getFullYear() 从 Date 对象以四位数字返回年份 date.getHours() 返回 Date 对象的小时 (0 ~

  • Javascript基础回顾之(一) 类型

    本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者那里的一知半解,所以决定先花一些时间整理一下这些基础知识和大家分享. 刚开始是打算写一篇的,但是后来写着写着就发现越来越多,所以决定还是写一个系列吧.本系列所有内容都是涉及Javascript基础的,没有时髦的玩意儿,但是我相信这些基础的东西会有助于你理解那些有趣的东西的. Javascript基础

  • javascript判断回文数详解及实现代码

    javascript判断回文数 概要: 回文"是指正读反读都能读通的句子,它是古今中外都有的一种修辞方式和文字游戏,如"我为人人,人人为我"等.在数学中也有这样一类数字有这样的特征,成为回文数(palindrome number). 设n是一任意自然数.若将n的各位数字反向排列所得自然数n1与n相等,则称n为一回文数.例如,若n=1234321,则称n为一回文数:但若n=1234567,则n不是回文数. 注意: 1.偶数个的数字也有回文数124421     2.小数没有回文

  • 理解javascript中的Function.prototype.bind的方法

    在初学Javascript时,我们也许不需要担心函数绑定的问题,但是当我们需要在另一个函数中保持上下文对象this时,就会遇到相应的问题了,我见过很多人处理这种问题都是先将this赋值给一个变量(比如self._this.that等),尤其是var that = this是我见的最多的,这样当你改变环境之后就可以使用它.这些都是可以的,但是还有一种更好的.更专有的方法,那就是使用Function.prototype.bind,下面进行详尽的讲解. 第一部分:需要解决的问题 首先看下面的代码 va

  • Javascript中数组去重与拍平的方法示例

    数组的判断 在说如何进行数组的去重和拍平之前,先说一下怎么判断数组,因为要进行数组的处理当然要先判断下传过来的数据是不是数组. 首先我们都知道js的数据类型只有5种,分别是Undefined.Null.Boolean.Number和String,数组只是一个对象,用typeof([])返回的结果知识一个Object的字符串,因此我们需要通过其他手段来判断它,这里就说两种方法. 第一种用instenceof方法 instanceof是ES5提供的一个方法,它可以用来判断实例是否是某个类的实例,例如

  • JavaScript数组复制详解

    前面的话   前面的博文中介绍了对象拷贝,本文将详细介绍数组复制 push function copyArray(arr){ var result = []; for(var i = 0; i < arr.length; i++){ result.push(arr[i]); } return result; } var obj1=[1,2,3]; var obj2=copyArray(obj1); console.log(obj1); //[1,2,3] console.log(obj2); /

  • JavaScript实现时钟滴答声效果

    下面一段代码给大家分享js实现时钟滴答声功能,具体代码如下所示: <!DOCTYPE html> <html> <head> <meta charset="utf8"> <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"> <meta name="keywords" content=&qu

  • Javascript中 带名 匿名 箭头函数的重要区别(推荐)

    带名函数是指函数显示地给出了一个名字的函数,function abs(x){}.匿名函数是指函数只带有function这个关键字,而没有像abs这种函数名称的函数,如function(){}.ES6标准新增了一种新的函数:Arrow Function(箭头函数)箭头函数表面上相当于匿名函数,并且简化了函数定义.它们各自的区别是什么呢? 1 带名和匿名函数的区别 区别:匿名函数需要讲地址赋值给另一个变量let a,然后再用a来调用函数:而带名函数因为显示地给出了函数名称,所以可以直接用这个函数名称

随机推荐