JavaScript常用進(jìn)制轉(zhuǎn)換及位運(yùn)算實(shí)例解析
前言
在一般的代碼中很少會(huì)接觸到進(jìn)制和位運(yùn)算,但這不代表我們可以不去學(xué)習(xí)它。作為一位編程人員,這些都是基礎(chǔ)知識(shí)。如果你沒有學(xué)過這方面的知識(shí),也不要慌,接下來(lái)的知識(shí)并不會(huì)很難。本文你將會(huì)學(xué)習(xí)到:
- 進(jìn)制轉(zhuǎn)換
- 按位操作符
- JavaScript進(jìn)制轉(zhuǎn)換
- 手動(dòng)實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換
進(jìn)制轉(zhuǎn)換
以下使用常見的十進(jìn)制和二進(jìn)制轉(zhuǎn)換作為例子,其他進(jìn)制的轉(zhuǎn)換也是大同小異,感興趣可以自己琢磨下。
十進(jìn)制轉(zhuǎn)二進(jìn)制
根據(jù) “逢十進(jìn)一” 的法則進(jìn)行計(jì)數(shù)時(shí),每十個(gè)相同的單位組成一個(gè)和它相鄰的較高的單位,這種計(jì)數(shù)法叫做十進(jìn)制計(jì)數(shù)法,簡(jiǎn)稱十進(jìn)制。這種是我們最常用的計(jì)數(shù)法。
整數(shù)
整數(shù)使用 “除二取余,逆序排列” 來(lái)轉(zhuǎn)換為二進(jìn)制,下面是18轉(zhuǎn)換為二進(jìn)制的例子:
// 除二取余
18 / 2 = 9...0
9 / 2 = 4...1
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...1// 倒序排列
10010
就這么簡(jiǎn)單,將得出的余數(shù)逆序排列,即可得出18的二進(jìn)制表示
小數(shù)
小數(shù)使用的是 “乘二取整,順序排列”,由于方法不同需要分開計(jì)算。下面是16.125轉(zhuǎn)為二進(jìn)制的例子:
16 / 2 = 8...0
8 / 2 = 4...0
4 / 2 = 2...0
2 / 2 = 1...0
1 / 2 = 0...10.125 * 2 = 0.25
0.25 * 2 = 0.5
0.5 * 2 = 110000.001
將小數(shù)相乘的結(jié)果,取結(jié)果的整數(shù)順序排列,得出小數(shù)位的二進(jìn)制表示
二進(jìn)制轉(zhuǎn)十進(jìn)制
根據(jù) “逢二進(jìn)一 ” 的法則進(jìn)行計(jì)數(shù)時(shí),每?jī)蓚€(gè)相同的單位組成一個(gè)和它相鄰的較高的單位,這種計(jì)數(shù)法叫做二進(jìn)制計(jì)數(shù) 法,簡(jiǎn)稱二進(jìn)制。用二進(jìn)制計(jì)數(shù)時(shí),只需用兩個(gè)獨(dú)立的符號(hào)“0”和“1” 來(lái)表示。
整數(shù)
整數(shù)使用 “按權(quán)相加” 法,即二進(jìn)制數(shù)首先寫成加權(quán)系數(shù)展開式,然后按十進(jìn)制加法規(guī)則求和。下面是101010轉(zhuǎn)換位十進(jìn)制的例子:
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
上面從右數(shù)依次是2的0次方,2的1次方,2的2次方... , 只取位數(shù)為1的結(jié)果,將它們相加就可以得到十進(jìn)制。
小數(shù)
10110.11轉(zhuǎn)十進(jìn)制:
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) 將其操作數(shù)(operands)當(dāng)作32位的比特序列(由0和1組成),前 31 位表示整數(shù)的數(shù)值,第 32 位表示整數(shù)的符號(hào),0 表示正數(shù),1 表示負(fù)數(shù)。例如,十進(jìn)制數(shù)18,用二進(jìn)制表示則為10010。按位操作符操作數(shù)字的二進(jìn)制形式,但是返回值依然是標(biāo)準(zhǔn)的JavaScript數(shù)值。
按位與( AND)
對(duì)于每一個(gè)比特位,只有兩個(gè)操作數(shù)相應(yīng)的比特位都是1時(shí),結(jié)果才為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)
在判斷一個(gè)數(shù)字奇偶時(shí),可以使用 a & 1
function assert(n) {
return n & 1 ? "奇數(shù)" : "偶數(shù)"
}
assert(3) // 奇數(shù)
因?yàn)槠鏀?shù)的二進(jìn)制最后一位是1,而1的二進(jìn)制最后一位也是1,通過 & 操作符得出結(jié)果為1
按位或(OR)
對(duì)于每一個(gè)比特位,當(dāng)兩個(gè)操作數(shù)相應(yīng)的比特位至少有一個(gè)1時(shí),結(jié)果為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)
將浮點(diǎn)數(shù)向下取整轉(zhuǎn)為整數(shù),可以使用 a | 0
12.1 | 0 // 12
12.9 | 0 // 12
按位異或(XOR)
對(duì)于每一個(gè)比特位,當(dāng)兩個(gè)操作數(shù)相應(yīng)的比特位有且只有一個(gè)1時(shí),結(jié)果為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)
反轉(zhuǎn)操作數(shù)的比特位,即0變成1,1變成0。
用法: ~ a
9 (base 10) = 00000000000000000000000000001001 (base 2)
--------------------------------
~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
通過兩次反轉(zhuǎn)操作,可將浮點(diǎn)數(shù)向下取整轉(zhuǎn)為整數(shù)
~~16.125 // 16
~~16.725 // 16
左移(Left shift)
將 a 的二進(jìn)制形式向左移 b (< 32) 比特位,右邊用0填充。
用法: a << b
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)
左移一位相當(dāng)于在原數(shù)字基礎(chǔ)上乘2,利用這一特點(diǎn),實(shí)現(xiàn)2的n次方:
function power(n) {
return 1 << n
}
power(3) // 8
有符號(hào)右移
將 a 的二進(jìn)制表示向右移 b (< 32) 位,丟棄被移出的位。
用法: a >> b
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
相比之下, -9 >> 2 得到 -3,因?yàn)榉?hào)被保留了。
-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)
與左移相反,右移一位在原數(shù)字基礎(chǔ)上除以2
64 >> 1 // 32
無(wú)符號(hào)右移
將 a 的二進(jìn)制表示向右移 b (< 32) 位,丟棄被移出的位,并使用 0 在左側(cè)填充。
用法: a >>> b
在非負(fù)數(shù)來(lái)說(shuō), 9 >>>2 和 9 >> 2 都是一樣的結(jié)果
9 (base 10): 00000000000000000000000000001001 (base 2)
--------------------------------
9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
而對(duì)于負(fù)數(shù)來(lái)說(shuō),結(jié)果就大有不同了,因?yàn)?>>> 不保留符號(hào),當(dāng)負(fù)數(shù)無(wú)符號(hào)右移時(shí),會(huì)使用0填充
-9 (base 10): 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
可以使用無(wú)符號(hào)右移來(lái)判斷一個(gè)數(shù)的正負(fù)
function isPos(n) { return (n === (n >>> 0)) ? true : false; } isPos(-1); // false isPos(1); // true
雖然 -1 >>> 0 不會(huì)發(fā)生右移,但 -1 的二進(jìn)制碼已經(jīng)變成了正數(shù)的二進(jìn)制碼, -1 >>> 0 結(jié)果為4294967295
Javascript進(jìn)制轉(zhuǎn)換
toString
toString 常用于將一個(gè)變量轉(zhuǎn)為字符串,或是判斷一個(gè)變量的類型,例如:
let arr = []
Object.prototype.toString.call(arr) // [object Array]
你應(yīng)該沒想過 toString 可以用于進(jìn)制轉(zhuǎn)換,請(qǐng)看下面例子:
(18).toString(2) // 10010(base 2)
(18).toString(8) // 22 (base 8)
(18).toString(16) // 12 (base 16)
參數(shù)規(guī)定表示數(shù)字的基數(shù),是 2 ~ 36 之間的整數(shù),若省略該參數(shù),則使用基數(shù) 10。該參數(shù)可以理解為轉(zhuǎn)換后的進(jìn)制表示。
parseInt
parseInt 常用于數(shù)字取整,它同樣可以傳入?yún)?shù)用于進(jìn)制轉(zhuǎn)換,請(qǐng)看下面例子:
parseInt(10010, 2) // 18 (base 10)
parseInt(22, 8) // 18 (base 10)
parseInt(12, 16) // 18 (base 10)
第二個(gè)參數(shù)表示要解析的數(shù)字的基數(shù),該值介于 2 ~ 36 之間。如果省略該參數(shù)或其值為 0,則數(shù)字將以 10 為基礎(chǔ)來(lái)解析。如果該參數(shù)小于 2 或者大于 36,則 parseInt 將返回 NaN。
記得有道面試題是這樣的:
// 問:返回的結(jié)果
[1, 2, 3].map(paseInt)
接下來(lái),我們來(lái)一步一步的看下過程發(fā)生了什么?
parseInt(1, 0) // 基數(shù)為 0 時(shí),以 10 為基數(shù)進(jìn)行解析,結(jié)果為 1
parseInt(2, 1) // 基數(shù)不符合 2 ~ 36 的范圍,結(jié)果為 NaN
parseInt(3, 2) // 這里以 2 為基數(shù)進(jìn)行解析,但 3 很明顯不是一個(gè)二進(jìn)制表示,故結(jié)果為 NaN//題目結(jié)果為
[1, NaN, NaN]
手動(dòng)實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換
雖然 JavaScript 為我們內(nèi)置了進(jìn)制轉(zhuǎn)換的函數(shù),但手動(dòng)實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換有利于我們理解過程,提高邏輯能力。對(duì)于初學(xué)者來(lái)說(shuō)也是一個(gè)很不錯(cuò)的練習(xí)例子。以下只簡(jiǎn)單實(shí)現(xiàn)非負(fù)整數(shù)的轉(zhuǎn)換。
十進(jìn)制轉(zhuǎn)二進(jìn)制
基于 “除二取余” 思路實(shí)現(xiàn)
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
二進(jìn)制轉(zhuǎn)十進(jìn)制
基于 “取冪相加” 思路實(shí)現(xiàn)
function toDecimal(value) { let bits = value.toString().split('') let res = 0 while (bits.length) { let bit = bits.shift() if (bit == 1) { // ** 為冪運(yùn)算符,如:2**3 為 8 res += 2 ** bits.length } } return res }
使用
toDecimal(10011) // 19
toDecimal(11111) // 33
寫在最后
本文為大家介紹了進(jìn)制和位運(yùn)算的相關(guān)知識(shí),旨在溫故知新。我們只需要大概了解就好,因?yàn)樵陂_發(fā)中真的用得少,至少我只用過 ~~ 來(lái)取整。而類似于~~這種取整操作還是盡量少用為好,對(duì)于其他開發(fā)者來(lái)說(shuō),可能會(huì)影響到代碼可讀性。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- nodejs 十六進(jìn)制字符串型數(shù)據(jù)與btye型數(shù)據(jù)相互轉(zhuǎn)換
- javascript十六進(jìn)制數(shù)字和ASCII字符之間的轉(zhuǎn)換方法
- JS中的進(jìn)制轉(zhuǎn)換以及作用
- javascript實(shí)現(xiàn)的字符串與十六進(jìn)制表示字符串相互轉(zhuǎn)換方法
- JavaScript實(shí)現(xiàn)把rgb顏色轉(zhuǎn)換成16進(jìn)制顏色的方法
- Javascript實(shí)現(xiàn)顏色rgb與16進(jìn)制轉(zhuǎn)換的方法
- JavaScript轉(zhuǎn)換二進(jìn)制編碼為ASCII碼的方法
- 使用JavaScript進(jìn)行進(jìn)制轉(zhuǎn)換將字符串轉(zhuǎn)換為十進(jìn)制
相關(guān)文章
淺析JavaScript中l(wèi)et與const命令的區(qū)別
這篇文章主要為大家詳細(xì)介紹了JavaScript中l(wèi)et命令與const命令的用法及區(qū)別,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考下2023-09-09一文教你徹底學(xué)會(huì)JavaScript手寫防抖節(jié)流
其實(shí)防抖和節(jié)流不僅僅在面試中會(huì)讓大家手寫,在實(shí)際項(xiàng)目中也可以起到性能優(yōu)化的作用,所以還是很有必要掌握的。本文就帶大家徹底學(xué)會(huì)JavaScript手寫防抖節(jié)流,需要的可以參考一下2022-11-11javascript數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹實(shí)現(xiàn)方法
這篇文章主要介紹了javascript數(shù)據(jù)結(jié)構(gòu)之二叉搜索樹實(shí)現(xiàn)方法,較為詳細(xì)的分析了二叉搜索樹的概念、原理與JavaScript實(shí)現(xiàn)二叉搜索樹的方法,對(duì)于學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11JS動(dòng)態(tài)改變?yōu)g覽器標(biāo)題的方法
這篇文章主要介紹了JS動(dòng)態(tài)改變?yōu)g覽器標(biāo)題的方法,涉及JavaScript頁(yè)面元素結(jié)合時(shí)間函數(shù)動(dòng)態(tài)操作的相關(guān)技巧,需要的朋友可以參考下2016-04-04使用純javascript實(shí)現(xiàn)放大鏡效果
本文給大家分享的是使用純javascript實(shí)現(xiàn)放大鏡效果的代碼,并附上封裝的步驟,做電商程序的小伙伴們一定不要錯(cuò)過。2015-03-03js時(shí)間戳轉(zhuǎn)yyyy-MM-dd HH-mm-ss工具類詳解
這篇文章主要介紹了js時(shí)間戳轉(zhuǎn)yyyy-MM-dd HH-mm-ss工具類,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04用Javascript做flash做的事..才完成的一個(gè)類.Auntion Action var 0.1
用Javascript做flash做的事..才完成的一個(gè)類.Auntion Action var 0.1...2007-02-02ECMAScript6輪播圖實(shí)踐知識(shí)總結(jié)
最近萌生了用ECMAScript6寫一個(gè)輪播圖的想法,以前就知道ECMAScript6,但是一直沒有學(xué),現(xiàn)在終于下決心學(xué)了,本篇文章會(huì)總結(jié)在實(shí)踐中用到的ES6的知識(shí)。2016-08-08