JavaScript常用进制转换及位运算实例解析


Posted in Javascript onOctober 14, 2020

前言

在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它。作为一位编程人员,这些都是基础知识。如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难。本文你将会学习到:

  • 进制转换
  • 按位操作符
  • JavaScript进制转换
  • 手动实现进制转换

进制转换

以下使用常见的十进制和二进制转换作为例子,其他进制的转换也是大同小异,感兴趣可以自己琢磨下。

十进制转二进制

根据 “逢十进一” 的法则进行计数时,每十个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做十进制计数法,简称十进制。这种是我们最常用的计数法。

整数

整数使用 “除二取余,逆序排列” 来转换为二进制,下面是18转换为二进制的例子:

// 除二取余
18 / 2 = 9...0
9 / 2 = 4...1
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...1

// 倒序排列
10010

就这么简单,将得出的余数逆序排列,即可得出18的二进制表示

小数

小数使用的是 “乘二取整,顺序排列”,由于方法不同需要分开计算。下面是16.125转为二进制的例子:

16 / 2 = 8...0
8 / 2 = 4...0
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...1

0.125 * 2 = 0.25
0.25 * 2 = 0.5
0.5 * 2 = 1

10000.001

将小数相乘的结果,取结果的整数顺序排列,得出小数位的二进制表示

二进制转十进制

根据 “逢二进一 ” 的法则进行计数时,每两个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做二进制计数 法,简称二进制。用二进制计数时,只需用两个独立的符号“0”和“1” 来表示。

整数

整数使用 “按权相加” 法,即二进制数首先写成加权系数展开式,然后按十进制加法规则求和。下面是101010转换位十进制的例子:

2^5 2^4 2^3 2^2 2^1 2^0
1 0 1 0 1 0
------------------------
32 + 0 + 8 + 0 + 2 + 0 = 42

上面从右数依次是2的0次方,2的1次方,2的2次方... , 只取位数为1的结果,将它们相加就可以得到十进制。

小数

10110.11转十进制:

2^4 2^3 2^2 2^1 2^0 2^-1 2^-2
1 0 1 1 0 . 1 1
-------------------------------
16 + 0 + 4 + 2 + 0 + 0.5 + 0.25 = 22.75

按位操作符

按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),前 31 位表示整数的数值,第 32 位表示整数的符号,0 表示正数,1 表示负数。例如,十进制数18,用二进制表示则为10010。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。

按位与( AND)

对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
用法: a & b 。

9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)

在判断一个数字奇偶时,可以使用 a & 1

function assert(n) {
return n & 1 ? "奇数" : "偶数"
}
assert(3) // 奇数

因为奇数的二进制最后一位是1,而1的二进制最后一位也是1,通过 & 操作符得出结果为1

按位或(OR)

对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
用法: a | b

9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)

将浮点数向下取整转为整数,可以使用 a | 0

12.1 | 0 // 12
12.9 | 0 // 12

按位异或(XOR)

对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
用法: a ^ b

9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)

按位非(NOT)

反转操作数的比特位,即0变成1,1变成0。

用法: ~ a

9 (base 10) = 00000000000000000000000000001001 (base 2)
--------------------------------
~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)

通过两次反转操作,可将浮点数向下取整转为整数

~~16.125 // 16
~~16.725 // 16

左移(Left shift)

将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
用法: a << b

9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)

左移一位相当于在原数字基础上乘2,利用这一特点,实现2的n次方:

function power(n) {
return 1 << n
}
power(3) // 8

有符号右移

将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。

用法: a >> b

9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

相比之下, -9 >> 2 得到 -3,因为符号被保留了。

-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)

与左移相反,右移一位在原数字基础上除以2

64 >> 1 // 32

无符号右移

将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

用法: a >>> b

在非负数来说, 9 >>>2 和 9 >> 2 都是一样的结果

9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

而对于负数来说,结果就大有不同了,因为 >>> 不保留符号,当负数无符号右移时,会使用0填充

-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)

可以使用无符号右移来判断一个数的正负

function isPos(n) {
  return (n === (n >>> 0)) ? true : false;
}

isPos(-1); // false
isPos(1); // true

虽然 -1 >>> 0 不会发生右移,但 -1 的二进制码已经变成了正数的二进制码, -1 >>> 0 结果为4294967295

Javascript进制转换

toString

toString 常用于将一个变量转为字符串,或是判断一个变量的类型,例如:

let arr = []
Object.prototype.toString.call(arr) // [object Array]

你应该没想过 toString 可以用于进制转换,请看下面例子:

(18).toString(2) // 10010(base 2)
(18).toString(8) // 22 (base 8)
(18).toString(16) // 12 (base 16)

参数规定表示数字的基数,是 2 ~ 36 之间的整数,若省略该参数,则使用基数 10。该参数可以理解为转换后的进制表示。

parseInt

parseInt 常用于数字取整,它同样可以传入参数用于进制转换,请看下面例子:

parseInt(10010, 2) // 18 (base 10)
parseInt(22, 8) // 18 (base 10)
parseInt(12, 16) // 18 (base 10)

第二个参数表示要解析的数字的基数,该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果该参数小于 2 或者大于 36,则 parseInt 将返回 NaN。

记得有道面试题是这样的:

// 问:返回的结果
[1, 2, 3].map(paseInt)

接下来,我们来一步一步的看下过程发生了什么?

parseInt(1, 0) // 基数为 0 时,以 10 为基数进行解析,结果为 1
parseInt(2, 1) // 基数不符合 2 ~ 36 的范围,结果为 NaN
parseInt(3, 2) // 这里以 2 为基数进行解析,但 3 很明显不是一个二进制表示,故结果为 NaN

//题目结果为
[1, NaN, NaN]

手动实现进制转换

虽然 JavaScript 为我们内置了进制转换的函数,但手动实现进制转换有利于我们理解过程,提高逻辑能力。对于初学者来说也是一个很不错的练习例子。以下只简单实现非负整数的转换。

十进制转二进制

基于 “除二取余” 思路实现

function toBinary(value) {
  if (isNaN(Number(value))) {
    throw `${value} is not a number` 
  }
  let bits = []
  while (value >= 1) {
    bits.unshift(value % 2)
    value = Math.floor(value / 2)
  }
  return bits.join('')
}

使用

toBinary(36) // 100100
toBinary(12) // 1100

二进制转十进制

基于 “取幂相加” 思路实现

function toDecimal(value) {
 let bits = value.toString().split('')
 let res = 0
 while (bits.length) {
  let bit = bits.shift()
  if (bit == 1) {
   // ** 为幂运算符,如:2**3 为 8
   res += 2 ** bits.length
  }
 }
 return res
}

使用

toDecimal(10011) // 19
toDecimal(11111) // 33

写在最后

本文为大家介绍了进制和位运算的相关知识,旨在温故知新。我们只需要大概了解就好,因为在开发中真的用得少,至少我只用过 ~~ 来取整。而类似于~~这种取整操作还是尽量少用为好,对于其他开发者来说,可能会影响到代码可读性。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
In Javascript Class, how to call the prototype method.(three method)
Jan 09 Javascript
脚本之家贴图转换+转贴工具用到的js代码超级推荐
Apr 05 Javascript
javascript一些不错的函数脚本代码
Sep 10 Javascript
动态创建的表格单元格中的事件实现代码
Dec 30 Javascript
表单切换,用回车键替换Tab健(不支持IE)
Jul 20 Javascript
js 鼠标移动显示图片的简单实例
Dec 25 Javascript
js调用后台、后台调用前台等方法总结
Apr 17 Javascript
JS逆序遍历实现代码
Dec 02 Javascript
jQuery圆形统计图开发实例
Jan 04 Javascript
Bootstrap3.0建站教程(一)之bootstrap表单元素排版
Jun 01 Javascript
深入浅析JavaScript中的Function类型
Jul 09 Javascript
javaScript生成支持中文带logo的二维码(jquery.qrcode.js)
Jan 03 Javascript
Vue实现鼠标经过文字显示悬浮框效果的示例代码
Oct 14 #Javascript
JavaScript本地储存:localStorage、sessionStorage、cookie的使用
Oct 13 #Javascript
原生JS实现相邻月份日历
Oct 13 #Javascript
jquery简易手风琴插件的封装
Oct 13 #jQuery
原生js实现照片墙效果
Oct 13 #Javascript
js轮播图之旋转木马效果
Oct 13 #Javascript
Vue中正确使用Element-UI组件的方法实例
Oct 13 #Javascript
You might like
关于PHP的curl开启问题探讨
2014/04/08 PHP
PHP针对多用户实现更换头像功能
2016/09/04 PHP
Javascript实现的分页函数
2006/12/22 Javascript
jQuery html()等方法介绍
2009/11/18 Javascript
js function使用心得
2010/05/10 Javascript
基于jquery的分页控件(C#)
2011/01/06 Javascript
jQuery代码优化 选择符篇
2011/11/01 Javascript
制作jquery遮罩层效果导航菜单代码分享
2013/12/25 Javascript
jquery修改属性值实例代码(设置属性值)
2014/01/06 Javascript
可编辑下拉框的2种实现方式
2014/06/13 Javascript
使用jQuery实现星级评分代码分享
2014/12/09 Javascript
js 博客内容进度插件详解
2017/02/19 Javascript
Vue常用指令V-model用法
2017/03/08 Javascript
Vue.directive自定义指令的使用详解
2017/03/10 Javascript
jQuery实现页码跳转式动态数据分页
2017/12/31 jQuery
JQuery实现table中tr上移下移的示例(超简单)
2018/01/08 jQuery
JS实现常见的查找、排序、去重算法示例
2018/05/21 Javascript
vue限制输入框只能输入8位整数和2位小数的代码
2019/11/06 Javascript
vue实现简单跑马灯效果
2020/05/25 Javascript
JavaScript图片旋转效果实现方法详解
2020/06/28 Javascript
Vue实现手机计算器
2020/08/17 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
2020/12/16 Javascript
Python中动态获取对象的属性和方法的教程
2015/04/09 Python
Python基于pygame实现的font游戏字体(附源码)
2015/11/11 Python
Python中字符串的修改及传参详解
2016/11/30 Python
详解Python import方法引入模块的实例
2017/08/02 Python
python之django母板页面的使用
2018/07/03 Python
Python实现随机漫步功能
2018/07/09 Python
python logging.info在终端没输出的解决
2020/05/12 Python
腾讯技术类校园招聘笔试试题
2014/05/06 面试题
测试工程师岗位职责
2013/11/28 职场文书
付款委托书范本
2014/04/04 职场文书
在人间读书笔记
2015/06/30 职场文书
Pytorch使用shuffle打乱数据的操作
2021/05/20 Python
react antd实现动态增减表单
2021/06/03 Javascript
Netty分布式客户端处理接入事件handle源码解析
2022/03/25 Java/Android