JavaScript 中的二進(jìn)制散列值和權(quán)限設(shè)計(jì)

不管是前端還是后端的伙伴,在工作中會(huì)經(jīng)常遇到權(quán)限控制的場景,業(yè)務(wù)上無非就幾種權(quán)限:頁面權(quán)限、操作權(quán)限、數(shù)據(jù)權(quán)限,不同公司根據(jù)業(yè)務(wù)需要都采取不同的方法區(qū)控制權(quán)限,我們這里討論一下使用 JavaScript 中的位運(yùn)算符來控制權(quán)限。

進(jìn)制類型

JavaScript 中提供的進(jìn)制表示方法有四種:十進(jìn)制、二進(jìn)制、十六進(jìn)制、八進(jìn)制。
對于數(shù)值字面量,主要使用不同的前綴來區(qū)分:

  1. 十進(jìn)制:取值數(shù)字 0-9;不用前綴。
  2. 二進(jìn)制(Binary): 取值數(shù)字 0 和 1 ;前綴 0b 或 0B。
  3. 十六進(jìn)制(Hexadecimal):取值數(shù)字 0-9 和 a-f ;前綴 0x 或 0X。
  4. 八進(jìn)制(Octal):取值數(shù)字 0-7 ;前綴 0o 或 0O (ES6規(guī)定)。

位運(yùn)算符

什么是位運(yùn)算符?
位運(yùn)算符指的是二進(jìn)制位的運(yùn)算,先將十進(jìn)制數(shù)轉(zhuǎn)成二進(jìn)制后再進(jìn)行運(yùn)算。 在二進(jìn)制位運(yùn)算中,1表示true,0表示false。
JavaScript 中的按位操作符有:

運(yùn)算符 用法 描述
按位與(AND) A & B 如果對應(yīng)的二進(jìn)制位都為 1,則該二進(jìn)制位為 1
按位或(OR) A 或 B 如果對應(yīng)的二進(jìn)制位有一個(gè)為 1,則該二進(jìn)制位為 1
按位異或(XOR) A ^ B 如果對應(yīng)的二進(jìn)制位只有一個(gè)為 1,則該二進(jìn)制位為 1
按位非(NOT) ~A 反轉(zhuǎn)所有二進(jìn)制位,即 1 轉(zhuǎn)換為 0,0 轉(zhuǎn)換為 1
按位左移 A << B 將所有二進(jìn)制位統(tǒng)一向左移動(dòng)指定的位數(shù),并在最右側(cè)補(bǔ) 0
按位右移 A >> B 按位右移(有符號右移):將所有二進(jìn)制位統(tǒng)一向右移動(dòng)指定的位數(shù),并拷貝最左側(cè)的位來填充左側(cè)
無符號右移 A >>> B 按位右移零(無符號右移):將所有二進(jìn)制位統(tǒng)一向右移動(dòng)指定的位數(shù),并在最左側(cè)補(bǔ) 0

示例:

const A = 0101,B = 0001
// 按位與(AND)
A & B = 0001

// 按位或(OR)
A | B = 0101

// 按位異或(XOR)
A ^ B = 0100

// 按位非(NOT)
~A = 1010

// 按位左移
A << 1 = 1010

// 按位右移
A >> 1 = 0010

// 無符號右移
A >>> 1 = 0010

位運(yùn)算符在工作中的應(yīng)用得比較少,但有時(shí)候它可以很巧妙地解決我們工作中一些問題。

運(yùn)用場景

在傳統(tǒng)的權(quán)限系統(tǒng)中,不同的權(quán)限之間存在很多關(guān)聯(lián)關(guān)系,而且有很多種權(quán)限組合方式,在這種情況下,權(quán)限就越難以維護(hù)。這種情況我們就可以使用位運(yùn)算符,可以很巧妙地解決這個(gè)問題。

假設(shè)我們現(xiàn)在權(quán)限系統(tǒng)中有4種基本權(quán)限:可讀、可寫、創(chuàng)建、刪除。
那么我們可以定義4個(gè)二進(jìn)制變量表示:

// 所有權(quán)限碼的二進(jìn)制數(shù)形式,有且只有一位值為 1,其余全部為 0
const READ = 0b1000 // 可讀
const WRITE = 0b0100 // 可寫
const CREATE = 0b0010 // 創(chuàng)建
const DELETE = 0b0001 // 刪除

權(quán)限操作

  1. 使用 按位或(OR) 添加權(quán)限:
// 賦予用戶全部權(quán)限
const ALL = READ | WRITE | CREATE | DELETE 

console.log(ALL)
// 結(jié)果位 1111,每個(gè)位置的1就代表擁有這個(gè)權(quán)限,這里全部是1,就代表擁有全部權(quán)限。

// 同樣的,這些權(quán)限可以自由組合
const READ_AND_WRITE = READ | WRITE  // 可讀和可寫,結(jié)果為 1100
const READ_AND_CREATE = READ | CREATE  // 可讀和創(chuàng)建,結(jié)果為 1010
const WRITE_AND_DELETE = WRITE | DELETE  // 可寫和刪除,結(jié)果為 0101
  1. 使用 按位與(AND) 校驗(yàn)權(quán)限:
// 比如我們拿到一個(gè)用戶的權(quán)限,我們怎么根據(jù)返回的數(shù)據(jù)判斷是否擁有某個(gè)權(quán)限呢?

// 假設(shè)現(xiàn)在返回了 擁有可讀可寫的權(quán)限組合:1100
const auth = READ | WRITE  // 可讀和可寫,結(jié)果為 1100

// 判斷是否包含 READ 權(quán)限
const isRead = (auth & READ) === READ // true

// 是否包含 DELETE 權(quán)限
const isDelete = (auth & DELETE) === DELETE // false
  1. 使用 按位非(NOT) 剔除權(quán)限:
// 全部權(quán)限
const ALL = READ | WRITE | CREATE | DELETE 

// 如果要剔除 WRITE 權(quán)限,應(yīng)該怎么做呢,先執(zhí)行 ~ 取反,再執(zhí)行 & 運(yùn)算
const notWrite = ALL & ~WRITE // 輸出 1011
// 剔除 DELETE 權(quán)限
const notDelete = ALL & ~DELETE // 輸出 1110

局限性

本文提到的這種位運(yùn)算符方案,有一定的前提條件:

  1. 每種權(quán)限碼都是唯一的,有且只有一位值為 1。
  2. 一個(gè)數(shù)字的范圍只能在 -(2^53 -1) 和 2^53 -1 之間,如果權(quán)限系統(tǒng)設(shè)計(jì)得比較龐大,這種方式可能不合適。

不過總的來說,這種方式在中小型業(yè)務(wù)中應(yīng)該夠用了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容