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 相关文章推荐
用jQuery打造TabPanel效果代码
May 22 Javascript
js面向对象设计用{}好还是function(){}好(构造函数)
Oct 23 Javascript
JS实现Enter键跳转及控件获得焦点
Aug 12 Javascript
js返回上一页并刷新的多种实现方法
Feb 26 Javascript
jQuery多媒体插件jQuery Media Plugin使用详解
Dec 19 Javascript
js的各种排序算法实现(总结)
Jul 23 Javascript
JavaScript选取(picking)和反选(rejecting)对象的属性方法
Aug 16 Javascript
Node.js中Koa2在控制台输出请求日志的方法示例
May 02 Javascript
微信小程序登录对接Django后端实现JWT方式验证登录详解
Jul 29 Javascript
微信用户访问小程序的登录过程详解
Sep 20 Javascript
使用JS实现鼠标放上图片进行放大离开实现缩小功能
Jan 27 Javascript
JavaScript使用canvas绘制坐标和线
Apr 28 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 Token(令牌)设计
2008/03/15 PHP
PHP 冒泡排序算法的实现代码
2010/08/08 PHP
PHP面向对象学习笔记之一 基础概念
2012/10/06 PHP
CodeIgniter框架提示Disallowed Key Characters的解决办法
2014/04/21 PHP
PHP实现简单数字分页效果
2015/07/26 PHP
PHP如何通过AJAX方式实现登录功能
2015/11/23 PHP
基于jquery点击自以外任意处,关闭自身的代码
2012/02/10 Javascript
IE6/IE7中JavaScript json提示缺少标识符、字符串或数字问题处理
2014/12/16 Javascript
js的各种排序算法实现(总结)
2016/07/23 Javascript
JS正则获取HTML元素的方法
2017/03/31 Javascript
js 监控iframe URL的变化实例代码
2017/07/12 Javascript
Angular 5.x 学习笔记之Router(路由)应用
2018/04/08 Javascript
nodejs异步编程基础之回调函数用法分析
2018/12/26 NodeJs
vue element-ui table组件动态生成表头和数据并修改单元格格式 父子组件通信
2019/08/15 Javascript
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
2019/08/23 Javascript
详解Vue中的Props与Data细微差别
2020/03/02 Javascript
基于js实现逐步显示文字输出代码实例
2020/04/02 Javascript
小程序实现左滑删除的效果的实例代码
2020/10/19 Javascript
Python调用C/C++动态链接库的方法详解
2014/07/22 Python
python保存字符串到文件的方法
2015/07/01 Python
详解Golang 与python中的字符串反转
2017/07/21 Python
Python正则表达式知识汇总
2017/09/22 Python
python多进程中的内存复制(实例讲解)
2018/01/05 Python
使用Python脚本zabbix自定义key监控oracle连接状态
2019/08/28 Python
Python pyautogui模块实现鼠标键盘自动化方法详解
2020/02/17 Python
详解如何用canvas画一个微笑的表情
2019/03/14 HTML / CSS
德国最新街头服饰网上商店:BODYCHECK
2019/09/15 全球购物
写给爸爸的道歉信
2014/01/15 职场文书
个人借款担保书
2014/04/02 职场文书
《菜园里》教学反思
2014/04/17 职场文书
幼儿园六一活动总结
2014/08/27 职场文书
机械工程及自动化专业求职信
2014/09/03 职场文书
查摆剖析材料范文
2014/09/30 职场文书
营业员岗位职责
2015/02/11 职场文书
寒假致家长的一封信
2015/10/10 职场文书
优秀党员主要事迹材料
2015/11/04 职场文书