JavaScript 之 位运算

一、简介

​ JavaScript的位运算符是将进行运算的数字(八进制、十进制、十六进制等)转换为32位的二进制串,超过 32 位的数字会丢弃其最高有效位,只保留后32位二进制串。然后再对每一位进行运算。但运算后得出的结果,会再次转换成标准的十进制的数字,然后返回。

注意: 如果进行位运算的数字是负数,则我们需要使用该负数的32位二进制补码来进行位运算。同理,如果运算后的结果为正数,则运算后的二进制串就是结果数值的二进制形式,如果运算后的结果为负数,则运算后的二进制串是结果数值的二进制补码形式。

​ 位运算符通常在处理大整数、位掩码、图形、加密等情况下使用,在日常编程工作中并不常用,对于一般的数字运算,使用常规的算术运算符即可。

二、前置知识

1、JavaScript数字进制相关知识:
  • 十进制整数字面量由一串数字序列组成,且没有前缀 0。
  • 八进制的整数以 0(或 0O、0o)开头,只能包括数字 0-7。
  • 十六进制整数以 0x(或 0X)开头,可以包含数字(0-9)和字母 a~f 或 A~F。
  • 二进制整数以 0b(或 0B)开头,只能包含数字 0 和 1。
2、二进制补码

​ 二进制补码是一种表示有符号整数的方法。在计算机中,整数通常以二进制形式存储和处理。补码表示法通过将负数转换为正数的补码形式,使得加法和减法操作可以在计算机中使用相同的硬件电路进行处理。

​ 在二进制补码中,最高位用于表示符号位,0表示正数,1表示负数。对于正数,其补码与其原码相同。而对于负数,其补码的计算方式如下:

​ ① 将负数的绝对值转换为二进制原码形式。

​ ② 对该二进制数取反(即将0变为1,将1变为0)。

​ ③ 对取反后的二进制数加1。

​ 例如,假设我们要表示-5的补码。首先,将-5的绝对值转换为二进制,得到 00000101。然后对其取反,得到 11111010。最后,对取反后的二进制数加1,得到 11111011,这就是-5的补码表示。如果想要将补码转换为原数值,只需要倒序进行操作即可。

三、单运算符

基础代码:
    // 声明一个十六进制变量let a = 0x10;// 声明一个十进制变量let b = 10;// 声明一个八进制变量let c = 0o22;// 获取a、b、c的二进制console.log(a.toString(2)); // 10000console.log(b.toString(2)); // 1010console.log(c.toString(2)); // 10010
1、&(按位与)

​ 该运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行&(与)操作。如果对应位的两个数字都为1,则该位运算的结果就为1,否则为0

    // a、b、c 两两进行按位与运算 console.log(a & b); // 10000 & 1010 = 00000 = 0console.log(b & c); // 1010 & 10010 = 00010 = 2console.log(a & c); // 10000 & 10010 = 10000 = 16// 负数进行按位与运算 console.log(-5 & 5); // 11111011 & 00000101 = 00000001 = 1console.log(-10 & -18); // 11110110 & 11101110 = 11100110(补码) = -26 
2、|(按位或)

​ 该运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行|(或)操作。如果对应位的两个数字中存在一个以上的1,则该位运算的结果就为1,否则为0

    // a、b、c 两两进行按位或运算console.log(a | b); // 10000 | 1010 = 11010 = 26console.log(b | c); // 1010 | 10010 = 11010 = 26console.log(a | c); // 10000 | 10010 = 10010 = 18// 负数进行按位或运算console.log(-5 | 5); // 11111011 | 00000101 = 11111111(补码) = -1console.log(-10 | -18); // 11110110 | 11101110 = 11111110(补码) = -2
3、^(按位异或)

​ 该运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行^(异或)操作。如果对应位的两个数字不相同,则该位运算的结果就为1,否则为0

		// a、b、c 两两进行按位异或运算console.log(a ^ b); // 10000 ^ 1010 = 11010 = 26console.log(b ^ c); // 1010 ^ 10010 = 11000 = 24console.log(a ^ c); // 10000 ^ 10010 = 10 = 2// 负数进行按位异或运算console.log(-5 ^ 5); // 11111011 ^ 00000101 = 11111110(补码) = -2console.log(-10 ^ -18); // 11110110 ^ 11101110 = 00011000 = 24
4、~(按位非)

​ 该运算符表示将要进行运算的数字,先转换成32位的二进制串,再按位进行~(非)操作,也就是反转每一位,如果原位为1,则反转为0;如果原位为0,则反转为1

​ 但是要注意,在JavaScript中32 位有符号整数操作数根据补码运算规则进行反转,也就是说,最高有效位表示负数。

​ 在进行按位非运算时,任何数字 x 的运算结果都是 -(x + 1),例如,~-5 运算结果为 4。由于数字 ~-1~4294967295(2 ** 32 - 1)均使用 32 位表示形式,它们的运算结果均为 0

		// 进行按位非运算console.log(~a); // ~10000 = -17console.log(~b); // ~1010 = -11console.log(~c); // ~10010 = -19// 负数进行按位非运算console.log(~-5); // ~1111011(补码) = 0000100 = 4console.log(~-10); // ~11110110(补码) = 00001001 = 9
5、<<(左移)

​ 该运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向左移动运算符右侧数字的位数。由于向左移动,左边超出32的位数将会被清除,右边会空出位,填充0

​ 移动任意数字 x << y 位,得出 x * 2 ** y。 例如:9 << 3 等价于 9 * 2³ = 9 * 8 = 72

		// 进行左移运算console.log(a << 1); // 10000 << 1 = 100000 = 32console.log(b << 2); // 1010 << 2 = 101000 = 40console.log(c << 3); // 10010 << 3 = 10010000 = 144// 负数进行左移运算console.log(-5 << 1); // 11111011(补码) << 1 = 11110110(补码) = -10console.log(-10 << 2); // 11110110(补码) << 2 = 11101100(补码) = -40
6、>>(算术右移)

​ 该运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向右移动运算符右侧数字的位数。由于向右移动,右侧被移出的位会被丢弃,左侧空出的位会根据最左侧的符号位进行填充。

​ 因此负数进行算术右移的结果一定为负数,正数进行算术右移的结果一定为正数。

    // 进行算术右移运算console.log(a >> 1); // 10000 >> 1 = 01000 = 8console.log(b >> 2); // 1010 >> 2 = 0010 = 2console.log(c >> 3); // 10010 >> 3 = 00010 = 2// 负数进行算术右移运算console.log(-5 >> 1); // 11111011(补码) >> 1 = 11111101(补码) = -3console.log(-10 >> 2); // 11110110(补码) >> 2 = 11111101(补码) = -3
7、>>>(无符号右移)

​ 该运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向右移动运算符右侧数字的位数。由于向右移动,右侧被移出的位会被丢弃,左侧空出的位填充0

​ 因此无论正数还是负数,进行无符号右移的结果一定为非负数。

   // 进行无符号右移运算console.log(a >>> 1); // 10000 >>> 1 = 1000 = 8console.log(b >>> 2); // 1010 >>> 2 = 10 = 2console.log(c >>> 3); // 10010 >>> 3 = 10 = 2// 负数进行无符号右移运算console.log((-5 >>> 0).toString(2));console.log(-5 >>> 1); // 11111111111111111111111111111011(补码) >>> 1 = 0111111111111111111111111111101 = 2147483645console.log(-10 >>> 2); // 11111111111111111111111111110110(补码) >>> 2 = 00111111111111111111111111111101 = 1073741821

四、组合运算符

1、&=(按位与赋值)

​ 该组合运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行&(与)操作。然后再将运算后的结果赋值给运算符左边的变量。

    // a、b、c两两进行按位与赋值a &= b; // 10000 &= 1010 = 00000 = 0console.log(a); // 0b &= c; // 1010 &= 10010 = 00010 = 2console.log(b); // 2c &= a; // 10010 &= 00000 = 00000 = 0console.log(c); // 0// 负数进行按位与赋值let d = 10;d &= -5; // 1010 &= 11111011 = 1010 = 10console.log(d); // 10
2、|&(按位或赋值)

​ 该组合运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行|(或)操作。然后再将运算后的结果赋值给运算符左边的变量。

    // 进行按位或赋值a |= b; // 10000 |= 1010 = 11010 = 26console.log(a); // 26// 负数进行按位或赋值let e = 10;e |= -5; // 1010 | 11111011 = 11111111(补码) = -5console.log(e); // -5
3、^=(按位异或赋值)

​ 该组合运算符表示将两个进行运算的数字,先转换成32位的二进制串,再按位进行^(异或)操作。然后再将运算后的结果赋值给运算符左边的变量。

    // 进行按位异或赋值a ^= b; // 10000 ^= 1010 = 11010 = 26console.log(a); // 26// 负数进行按位异或赋值let f = 10;f ^= -5; // 1010 ^= 11111011 = 11110001(补码) = -15console.log(f); // -15
4、<<=(左移赋值)

​ 该组合运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向左移动运算符右侧数字的位数。最后再将运算的结果赋值给运算符左侧的变量。

​ 由于向左移动,左边超出32的位数将会被清除,右边会空出位,填充0

    // 进行左移赋值a <<= 1; // 10000 <<= 1 = 100000 = 32console.log(a); // 32// 负数进行左移赋值let g = -5;g <<= 1; // 11111011(补码) <<= 1 = 11110110(补码) = -10console.log(g); // -10
5、>>=(算术右移赋值)

​ 该组合运算符表示该运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向右移动运算符右侧数字的位数。最后再将运算的结果赋值给运算符左侧的变量。

​ 由于向右移动,右侧被移出的位会被丢弃,左侧空出的位会根据最左侧的符号位进行填充。因此负数进行算术右移的结果一定为负数,正数进行算术右移的结果一定为正数。

    // 进行算术右移赋值a >>= 1; // 10000 >>= 1 = 01000 = 8console.log(a); // 8// 负数进行算术右移赋值let h = -5;h >>= 1; // 11111011(补码) >>= 1 = 11111101(补码) = -3console.log(h); // -3
6、>>>=(无符号右移赋值)

​ 该组合运算符表示该运算符表示将运算符左侧要进行运算的数字,先转换成32位的二进制串,然后再向右移动运算符右侧数字的位数。最后再将运算的结果赋值给运算符左侧的变量。

​ 由于向右移动,右侧被移出的位会被丢弃,左侧空出的位填充0。因此无论正数还是负数,进行无符号右移的结果一定为非负数。

    // 进行无符号右移赋值a >>>= 1; // 10000 >>>= 1 = 1000 = 8console.log(a); // 8// 负数进行无符号右移赋值let i = -5;i >>>= 1; // 11111011(补码) >>>= 1 = 0111111111111111111111111111101 = 2147483645console.log(i); // 2147483645

五、参考资料

位运算符

运算符

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 元类 metaclass 详解

元类&#xff08;metaclass&#xff09;是 Python 中一个高级且相对较少使用的概念。元类可以被视为类的类&#xff0c;它控制类的创建过程。 一、基本概念 在 Python 中&#xff0c;一切皆对象。为了避免混淆&#xff0c;我们约定两个术语&#xff1a; 类实例&#xff1a;当…

IPv6路由综合运用

一、基础配置: SWA: sw1(config)#host swA swA(config)#ipv6 ena swA(config)# vlan 100 swA(config-vlan100)#int vlan 100 swA(config-if-vlan100)#ipv6 ena swA(config-vlan100)#ip add 172.16.1.1 255.255.255.252 swA(config-if-vlan100)#int e1/0/24 swA(conf…

教育科学杂志教育科学杂志社教育科学编辑部2023年第12期部分目录

“思政教育联合思维导图”教学模式在肝病感染控制护理临床教学中的应用 黄雪霞;陈海涵;蒋雅文 中职语文教学中厚植爱国主义情怀的要点分析 苏琴 职业素养视角下中职计算机专业课程教学改革实践 李石 产教融合背景下高职院校产业学院建设模式的实践探索 郭洋 《工程制图与CAD》课…

数据结构学习 jz31 栈的压入、弹出序列

关键词&#xff1a;模拟 栈 不太熟&#xff0c;调了好一阵子。 题目&#xff1a;https://leetcode.cn/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/ 思路&#xff1a; 主要是利用一个辅助栈&#xff0c;来模拟这个过程&#xff0c;如果过程不行就返回失败。 int sig 0;如…

Java研学-分页查询

一 分页概述 1 介绍 将大量数据分段显示&#xff0c;避免一次性加载造成的内存溢出风险 2 真假分页 ① 真分页   一次性查询出所有数据存到内存&#xff0c;翻页从内存中获取数据&#xff0c;性能高但易造成内存溢出 ② 假分页   每次翻页从数据库中查询数据&#xff0c…

解决计算机中vcruntime140.dll错误!六种方法教你修复

什么是vcruntime140.dll文件呢&#xff1f;为什么会出现丢失的情况&#xff1f;如何解决这个问题呢&#xff1f;本文将为您详细介绍vcruntime140.dll文件的作用、丢失原因以及6个快速解决方法。 一、vcruntime140.dll是什么文件&#xff1f; vcruntime140.dll是Visual C Redi…

聚合收益协议 InsFi :打开铭文赛道全新叙事的旋转门

​“InsFi 协议构建了一套以铭文资产为基础的聚合收益体系&#xff0c;该体系正在为铭文资产捕获流动性、释放价值提供基础&#xff0c;该生态也正在成为铭文赛道掘金的新热土。” 在 2023 年年初&#xff0c;Ordinals 协议在比特币链上被推出后&#xff0c;为比特币链上带来了…

STC51+TLC2543+ADXL335+proteus

51单片机解析adxl335振动检测蜂鸣器报警课设 通过按键调整振动检测阈值 传感器介绍 TLC2543&#xff1a;12 位精密模数转换器&#xff0c;原理图与引脚功能描述如下所示&#xff1a; 引脚功能1~9、11、12模拟量输入通道10GND电源地13REF-为负基准电压端14REF为正基准电压端…

基于ssm的课程在线教学平台设计与实现论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统Java课程教学信息管理难度大&#xff0c;容错率低&#x…

Referring Expression Comprehension(REC)任务介绍以及相关数据集

Referring Expression Comprehension&#xff08;REC&#xff09;&#xff0c;即指称表达理解&#xff0c;任务是根据文本描述框出文本中提到的一个特定目标相关数据集&#xff1a; 是三个从 MSCOCO 中选取图像得到的数据集&#xff0c;数据集中对所有的 phrase 都有 bbox 的标…

【html】Video元素的属性介绍和用法

简言 HTML <video> 元素 用于在 HTML 或者 XHTML 文档中嵌入媒体播放器&#xff0c;用于支持文档内的视频播放。 平常若涉及到视频内容&#xff0c;就会使用到它。 video Video使用 只有一个视频源 只有一个视频的话&#xff0c;在\video元素中的src属性填入即可。 …

【工作周志】240108-240114

Q&#xff1a;set_property bitstream.config.timer_cfg 这样的配置用于哪里&#xff1f; A&#xff1a;https://www.cnblogs.com/lazypigwhy/p/10450406.html FPGA通过CPU远程升级方案_bitstream.config.timer_cfg-CSDN博客 Q&#xff1a;逛论坛有人问&#xff0c;reg也可以…

数据资产入表背后:中国To B数字化驶入“数据时代”

数据资产“入表”&#xff0c;更像是一剂通过颠覆旧的生产关系&#xff0c;从根上医治数字化转型的“良方”。 那么&#xff0c;数据资产到底是什么&#xff1f;以及在愈发被规范的数据市场大背景下&#xff0c;对中国的To B企业和To B服务商而言&#xff0c;正在或者即将发生…

快速解密Word密码工具,轻松获取文档权限

Word文档怎么解密、找回密码、去除密码&#xff1f;这是最简单的办法&#xff01; 文章&#xff1a;具体步骤如下&#xff1a;1.百度搜索【 密码帝官网 】&#xff0c;2.点击“立即开始”在用户中心上传需要解密的文件稍等片刻就能找找回密码。方法非常安全&#xff0c;不用下载…

RKE安装k8s及部署高可用rancher之证书通过cert-manager

1.安装rke和local集群 [rootnginx 2.5.8]# rke -v rke version v1.5.1 [rootnginx cert-manager]# rke up --config locale-cluster.ym [rootnginx 2.5.8]# cat locale-cluster.yml nodes:- address: 192.168.1.65internal_address: 192.168.1.65hostname_override: 192.168.…

【记忆化搜索】

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 前言 记忆化搜索是一种优化搜索算法的方法&#xff0c;它可…

框架自带sidebar配置

路由配置的页面 在这个框架里面,需要删除一些东西,在VueRouter里面,创建好两个路由,一个是由export default导出去的,一个是由export导出去的,有很多人问,为什么要创建两个路由呢? 为了后期的权限管理做准备&#xff0c; 为什么显示出来的只有一个路由的界面呢? 在路由注…

基于JavaWeb+BS架构+SpringBoot+Vue基于hive旅游数据的分析与应用系统的设计和实现

基于JavaWebBS架构SpringBootVue基于hive旅游数据的分析与应用系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1 概 述 5 1.1 研究背景 5 1.2 研究意义 5 1.3 研究内容…

探索sklearn中SVM模型的原理及使用案例

大家好&#xff0c;支持向量机&#xff08;Support Vector Machines&#xff0c;SVM&#xff09;是一种经典的机器学习算法&#xff0c;被广泛应用于分类和回归任务中。在sklearn库中&#xff0c;SVM模型提供了简单易用的API&#xff0c;使得开发者可以方便地应用SVM算法解决实…