有没有办法重构这个 AND 和 XOR 逻辑分支?
Is there a way to refactor this AND and XOR logical branch?
我有 2 个用户 ID,如果我只有一个或两个,我想执行不同但非常相似的逻辑。有没有办法合并这段代码,现在看起来很难看。
function getUserPermission(primaryId, secondaryId, role) {
let permission = userInfo.permissionList.filter( permission => {
//logical AND
if(primaryId && secondaryId){
// have both IDs, use both IDs
(permission.primaryId === primaryId && permission.secondaryId === secondaryId) && permission.role === role
}
//logical XOR
else if((primaryId && !secondaryId) || (!primaryId && secondaryId)) {
// have only 1 ID, use 1 ID
(permission.primaryId === primaryId || permission.secondaryId === secondaryId) && permission.role === role
}
})[0]
return permission
}
这样的事情怎么样?
if(!primaryId && !secondaryId) {
throw Error("No ID was provided");
}
let permission = userInfo.permissionList.filter(p => p.role === role);
if(primaryId) {
permission = permission.filter(p => p.primaryId === primaryId);
}
if(secondaryId) {
permission = permission.filter(p => p.secondaryId === secondaryId);
}
return permission[0];
function getUserPermission(primaryId, secondaryId, role) {
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!!primaryId || !!secondaryId)// at least one is populated
&& (!primaryId || primaryId === permission.primaryId)// if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId)// if secondary is populated, it needs to match
);
}
这与您的代码略有不同,如果没有匹配项,它将 returns 为 null,而您的代码会抛出异常。如果你想抛出,你总是可以把结果放在一个变量中并检查是否为 null。
首先,当两个 ID 都无效时,这个逻辑似乎无法处理。你会想以某种方式处理它(看起来其他两个答案到目前为止都包含这些内容)。
接下来,由于您只返回第一个匹配的权限,我建议您使用一种在找到第一个匹配后不会继续循环的解决方案。在这方面,对于此用例,Array.find()
比 Array.filter()
好得多。
如果我将其他答案放在一起,它会是这样的:
function getUserPermission(primaryId, secondaryId, role) {
if (!primaryId && !secondaryId) return null // at least one must be populated, why loop at all?
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!primaryId || primaryId === permission.primaryId) // if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId) // if secondary is populated, it needs to match
);
}
...但这并不能处理完全有效的 ID 恰好为 0 的情况。不过,这可能取决于您的数据。例如,您可能总是使用基于字符串的 ID。它还会在每个循环中检查有效的 ID(您可能会或可能不会非常满意)
考虑到这些潜在问题,我对您的 data/types 做了一些假设,并结合了一种更非正统的方法来尝试解决它们:
const getUserPermission = (primaryId = -1, secondaryId = -1, role = '') => {
if (primaryId < 0 && secondaryId < 0) return null
const conditions = [ p => p.role === role ]
.concat(primaryId >= 0 ? [ p => p.primaryId === primaryId ] : [])
.concat(secondaryId >= 0 ? [ p => p.secondaryId === secondaryId ] : [])
return userInfo.permissionList.find(p => conditions.every(fn => fn(p)))
}
...最后一个函数组成了一个函数数组,conditions
,用于检查每个权限。第一个符合所有条件的应该返回(理论上,至少 - 我没有测试它)
这个重构怎么样:
function getUserPermission(primaryId = undefined,secondaryId = undefined,role) {
primaryId === undefined && secondaryId === undefined && throw new Error("Ids are required");
const userPermission = userInfo.permissionList
.filter((permission) => role && permission.role === role)
.filter((permission) => primaryId && permission.primaryId === primaryId)
.filter(
(permission) => secondaryId && permission.secondaryId === secondaryId
);
return userPermission[0];
}
我有 2 个用户 ID,如果我只有一个或两个,我想执行不同但非常相似的逻辑。有没有办法合并这段代码,现在看起来很难看。
function getUserPermission(primaryId, secondaryId, role) {
let permission = userInfo.permissionList.filter( permission => {
//logical AND
if(primaryId && secondaryId){
// have both IDs, use both IDs
(permission.primaryId === primaryId && permission.secondaryId === secondaryId) && permission.role === role
}
//logical XOR
else if((primaryId && !secondaryId) || (!primaryId && secondaryId)) {
// have only 1 ID, use 1 ID
(permission.primaryId === primaryId || permission.secondaryId === secondaryId) && permission.role === role
}
})[0]
return permission
}
这样的事情怎么样?
if(!primaryId && !secondaryId) {
throw Error("No ID was provided");
}
let permission = userInfo.permissionList.filter(p => p.role === role);
if(primaryId) {
permission = permission.filter(p => p.primaryId === primaryId);
}
if(secondaryId) {
permission = permission.filter(p => p.secondaryId === secondaryId);
}
return permission[0];
function getUserPermission(primaryId, secondaryId, role) {
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!!primaryId || !!secondaryId)// at least one is populated
&& (!primaryId || primaryId === permission.primaryId)// if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId)// if secondary is populated, it needs to match
);
}
这与您的代码略有不同,如果没有匹配项,它将 returns 为 null,而您的代码会抛出异常。如果你想抛出,你总是可以把结果放在一个变量中并检查是否为 null。
首先,当两个 ID 都无效时,这个逻辑似乎无法处理。你会想以某种方式处理它(看起来其他两个答案到目前为止都包含这些内容)。
接下来,由于您只返回第一个匹配的权限,我建议您使用一种在找到第一个匹配后不会继续循环的解决方案。在这方面,对于此用例,Array.find()
比 Array.filter()
好得多。
如果我将其他答案放在一起,它会是这样的:
function getUserPermission(primaryId, secondaryId, role) {
if (!primaryId && !secondaryId) return null // at least one must be populated, why loop at all?
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!primaryId || primaryId === permission.primaryId) // if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId) // if secondary is populated, it needs to match
);
}
...但这并不能处理完全有效的 ID 恰好为 0 的情况。不过,这可能取决于您的数据。例如,您可能总是使用基于字符串的 ID。它还会在每个循环中检查有效的 ID(您可能会或可能不会非常满意)
考虑到这些潜在问题,我对您的 data/types 做了一些假设,并结合了一种更非正统的方法来尝试解决它们:
const getUserPermission = (primaryId = -1, secondaryId = -1, role = '') => {
if (primaryId < 0 && secondaryId < 0) return null
const conditions = [ p => p.role === role ]
.concat(primaryId >= 0 ? [ p => p.primaryId === primaryId ] : [])
.concat(secondaryId >= 0 ? [ p => p.secondaryId === secondaryId ] : [])
return userInfo.permissionList.find(p => conditions.every(fn => fn(p)))
}
...最后一个函数组成了一个函数数组,conditions
,用于检查每个权限。第一个符合所有条件的应该返回(理论上,至少 - 我没有测试它)
这个重构怎么样:
function getUserPermission(primaryId = undefined,secondaryId = undefined,role) {
primaryId === undefined && secondaryId === undefined && throw new Error("Ids are required");
const userPermission = userInfo.permissionList
.filter((permission) => role && permission.role === role)
.filter((permission) => primaryId && permission.primaryId === primaryId)
.filter(
(permission) => secondaryId && permission.secondaryId === secondaryId
);
return userPermission[0];
}