前端权限
前端权限一直都是备受关注的技术点.通过给项目引入了权限控制方案,可以满足我们灵活的调整用户访问或者操作的许可,我们可以将前端权限分为定义权限以及判断权限两步
举个栗子
当我们需要去处理一个权限的时候
例如我们需要给一个创建按钮添加权限的时候
定义权限:
canCreated=false|true
判断权限:
if(canCreated){
console.log('可以创建!')
}
else{
console.log('无法创建!')
}
当我们需要去处理多个权限的时候
当然我们日常开发中,需要更多考虑的是多个权限的时候如何去定义和判断权限
通过定义权限点实现权限
定义权限: 定义创建、删除、更新、查看按钮对应的权限点,并给该用户定义相关的权限
const canCreated=1001
const canDelete=1002
const canUpdate=1003
const canLook=1001
判断权限:
const userPermissionList=[1001,1003]
此时通过权限数组可以知道用户拥有创建和更新的权限
思考
但是不管是通过变量去定义或者是权限点去定义,都需要多个变量才能表达这个用户的权限, 如果我们为每种有可能出现的权限都写一个变量来标识, 那我们需要写 2 ^ 4 = 16 个变量还储存这些组合,如何通过一个变量去表达这个用户的权限尼?
通过位掩码 二进制实现权限
首先进行名词解释,什么是”位掩码“。位掩码(BitMask),是”位(Bit)“和”掩码(Mask)“的组合词。”位“指代着二进制数据当中的二进制位,而”掩码“指的是一串用于与目标数据进行按位操作的二进制数字。组合起来,就是”用一串二进制数字(掩码)去操作另一串二进制数字“的意思。明白了位掩码的作用以后,我们就可以通过它来对权限集二进制数进行操作了。
定义权限:
- 按位左移 创建对应二进制
const canCreated=1 //0b0001 1<<0
const canDelete=2 //0b0010 1<<1
const canUpdate=4 //0b0100 1<<2
const canLook=8 //0b1000 1<<3
- 按位或代表的就是多种处理方式
- 按位与来判断是否包含当前处理方式
当用户拥有【创建】、【删除】、【查看】权限的时候:
通过二进制按位或 代表多种方式( 如果相对应位都是0,则结果为0,否则为1 ):&
此时可以通过11来代表该用户拥有【创建】、【删除】、【查看】的权限
判断权限:
上文已经定义了用户拥有【创建】、【删除】、【查看】的权限,又如何判断是否用户某个权限尼?
通过二进制按位与 来判断是否包含当前处理方式( 如果相对应位都是1,则结果为1,否则为0 ):|
如上图可以判断用户拥有创建的权限,不拥有更新的权限
处理不定参数
当然我们还能通过位掩码来做更多的操作,比如在函数库lodash 中有下面的代码:
/**
* The base implementation of `clone` and `cloneDeep` which tracks
* traversed objects.
*
* @private
* @param {*} value The value to clone.
* @param {number} bitmask The bitmask flags.
* 1 - Deep clone
* 2 - Flatten inherited properties
* 4 - Clone symbols
* @param {Function} [customizer] The function to customize cloning.
* @param {string} [key] The key of `value`.
* @param {Object} [object] The parent object of `value`.
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
* @returns {*} Returns the cloned value.
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
let result
const isDeep = bitmask & CLONE_DEEP_FLAG
const isFlat = bitmask & CLONE_FLAT_FLAG
const isFull = bitmask & CLONE_SYMBOLS_FLAG
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value)
}
if (result !== undefined) {
return result
}
if (!isObject(value)) {
return value
}
const isArr = Array.isArray(value)
const tag = getTag(value)
if (isArr) {
result = initCloneArray(value)
if (!isDeep) {
return copyArray(value, result)
}
} else {
const isFunc = typeof value === 'function'
if (isBuffer(value)) {
return cloneBuffer(value, isDeep)
}
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
result = (isFlat || isFunc) ? {} : initCloneObject(value)
if (!isDeep) {
return isFlat
? copySymbolsIn(value, copyObject(value, keysIn(value), result))
: copySymbols(value, Object.assign(result, value))
}
} else {
if (isFunc || !cloneableTags[tag]) {
return object ? value : {}
}
result = initCloneByTag(value, tag, isDeep)
}
}
// Check for circular references and return its corresponding clone.
stack || (stack = new Stack)
const stacked = stack.get(value)
if (stacked) {
return stacked
}
stack.set(value, result)
if (tag == mapTag) {
value.forEach((subValue, key) => {
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack))
})
return result
}
if (tag == setTag) {
value.forEach((subValue) => {
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack))
})
return result
}
if (isTypedArray(value)) {
return result
}
const keysFunc = isFull
? (isFlat ? getAllKeysIn : getAllKeys)
: (isFlat ? keysIn : keys)
const props = isArr ? undefined : keysFunc(value)
arrayEach(props || value, (subValue, key) => {
if (props) {
key = subValue
subValue = value[key]
}
// Recursively populate clone (susceptible to call stack limits).
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack))
})
return result
}
cloneDeep文件中:
// 定义几种状态
const CLONE_DEEP_FLAG = 1
const CLONE_SYMBOLS_FLAG = 4
function cloneDeep(value) {
return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG)
}
此时:
function baseClone(value, bitmask, customizer, key, object, stack) {
// 0101 & 0001 => 0001 => 之后用的时候 if(isDeep) 会隐式转换成 true
const isDeep = bitmask & CLONE_DEEP_FLAG
// 0101 & 0010 => 0000 => 之后用的时候 if(isFlat) 会隐式转换成 false
const isFlat = bitmask & CLONE_FLAT_FLAG
// 0101 & 0100 => 0100 => 之后用的时候 if(isFull) 会隐式转换成 true
const isFull = bitmask & CLONE_SYMBOLS_FLAG
}