如何做到这一点
var has = Object.prototype.hasOwnProperty
var toString = Object.prototype.toString
function isEmpty(val) {
if (val == null) return true
if ('boolean' == typeof val) return false
if ('number' == typeof val) return val === 0
if ('string' == typeof val) return val.length === 0
if ('function' == typeof val) return val.length === 0
if (Array.isArray(val)) return val.length === 0
if (val instanceof Error) return val.message === ''
if (val.toString == toString) {
switch (val.toString()) {
case '[object File]':
case '[object Map]':
case '[object Set]': {
return val.size === 0
}
case '[object Object]': {
for (var key in val) {
if (has.call(val, key)) return false
}
return true
}
}
}
return false
}
module.exports = isEmpty
答案 0 :(得分:0)
如果无法拆分功能或使用OOP方法,则可以使用功能数组并对其进行迭代:
const has = Object.prototype.hasOwnProperty;
const toString = Object.prototype.toString;
function isEmpty(val) {
let isEmpty = null;
const checkFunctions = [
(val) => 'boolean' === typeof val ? false : null,
(val) => 'number' === typeof val ? val === 0 : null,
(val) => ['string', 'function'].includes(typeof val) ? val.length === 0 : null,
(val) => Array.isArray(val) ? val.length === 0 : null,
(val) => val instanceof Error ? val.message === '' : null,
(val) => val.toString == toString && ['[object File]', '[object Map]', '[object Set]'].includes(val.toString()) ? val.size === 0 : null,
(val) => {
if (val.toString == toString && val.toString() === '[object Object]') {
for (var key in val) {
if (has.call(val, key)) return false
}
return true;
}
}
];
for (let i = 0; i < checkFunctions.length; i++) {
isEmpty = checkFunctions[i](val);
if (isEmpty !== null) {
return isEmpty;
};
}
}
console.log(isEmpty(''), true);
console.log(isEmpty('Hallo'), false);
console.log(isEmpty(0), true);
console.log(isEmpty(1), false);
console.log(isEmpty({}), true);
console.log(isEmpty({a: 1}), false);
您还可以扩展JS的核心类型,然后代替isEmpty(val)编写val.isEmpty()。例如:
String.prototype.isEmpty = function() {return this.length === 0}
Array.prototype.isEmpty = function() {return this.length === 0}
console.log("".isEmpty(), true);
console.log("foo".isEmpty(), false);
console.log([].isEmpty(), true);
console.log([1,2,3].isEmpty(), false);
答案 1 :(得分:0)
我最近回答了一个非常相似的问题,它进一步详细介绍了认知复杂性的工作原理(请参见https://stackoverflow.com/a/62867219/7730554)。
但是,总的来说,我认为了解如果存在嵌套条件会进一步增加认知复杂性,这一点很重要。之所以进行这种计算,是因为人脑可以更好地处理按顺序编写的语句,而不是嵌套条件。因此,对于每个条件语句(if,switch,for循环等),将在+1上添加复杂度值。但是,对于每个嵌套条件,在最后一级之上会再加上+1。这意味着,在if中的if不仅会加+1,而且还会加+2。如果在if中,在if中,if将在第一个if中产生+1,在第二个if中产生+2,在第三个if中产生+3。如果您想更深入地了解这一点,建议您看一下:https://www.sonarsource.com/docs/CognitiveComplexity.pdf
因此,让我们分析一下您的方法中的高复杂度值首先起源于何处:
function isEmpty(val) {
if (val == null) return true // +1
if ('boolean' == typeof val) return false // +1
if ('number' == typeof val) return val === 0 // +1
if ('string' == typeof val) return val.length === 0 // +1
if ('function' == typeof val) return val.length === 0 // +1
if (Array.isArray(val)) return val.length === 0 // +1
if (val instanceof Error) return val.message === '' // +1
if (val.toString == toString) { // +1
switch (val.toString()) { // +2
case '[object File]':
case '[object Map]':
case '[object Set]': {
return val.size === 0
}
case '[object Object]': {
for (var key in val) { // +3
if (has.call(val, key)) return false // +4
}
return true
}
}
}
return false
}
如果您查看我添加的注释,则可以轻松地看到关于圈复杂度最成问题的代码所在的位置。这也与代码的人工可读性有关。
因此,提高可读性并同时降低认知复杂度的一个简单步骤就是寻找“ 早期回报 ”。
为了说明这一点,我简单地颠倒了* if(val.toString == toString)“语句,如果* val.toString!= toString”立即返回false:
function isEmpty(val) {
if (val == null) return true // +1
if ('boolean' == typeof val) return false // +1
if ('number' == typeof val) return val === 0 // +1
if ('string' == typeof val) return val.length === 0 // +1
if ('function' == typeof val) return val.length === 0 // +1
if (Array.isArray(val)) return val.length === 0 // +1
if (val instanceof Error) return val.message === '' // +1
if (val.toString != toString) { // +1
return false;
}
switch (val.toString()) { // +1
case '[object File]':
case '[object Map]':
case '[object Set]': {
return val.size === 0
}
case '[object Object]': {
for (var key in val) { // +2
if (has.call(val, key)) return false // +3
}
return true
}
}
}
现在,最后一个switch语句可以在if语句之外执行,并且我们将嵌套级别降低了一个。通过这种简单的更改,认知复杂性现在已经从17降到了14 。
您甚至可以更进一步,通过将返回值提取到变量中来更改最后一个case语句,或者从代码块中提取单独的方法。这样可以进一步降低isEmpty()方法的复杂性。
除了提取方法外,还可以使用声明性方法并使用,例如数组方法 find(),这将进一步降低认知的复杂性。
为了说明这个想法,我做了两个:
function isEmpty(val) {
if (val == null) return true // +1
if ('boolean' == typeof val) return false // +1
if ('number' == typeof val) return val === 0 // +1
if ('string' == typeof val) return val.length === 0 // +1
if ('function' == typeof val) return val.length === 0 // +1
if (Array.isArray(val)) return val.length === 0 // +1
if (val instanceof Error) return val.message === '' // +1
if (val.toString != toString) { // +1
return false;
}
return checkForComplexTypes(val)
}
function checkForComplexTypes(val) {
var result = null
switch (val.toString()) { // +1
case '[object File]':
case '[object Map]':
case '[object Set]': {
result = val.size === 0
}
case '[object Object]': {
result = Object.keys(val).find(key => has.call(val, key))
}
return result
}
}
这应该将 isEmpty()方法的认知复杂度降低到8 和整个代码包括提取的 checkForComplexTypes()函数的复杂度得分为9 。
注意:JavaScript目前不是我的主要语言,因此我不能完全保证最后一个重构步骤的正确性。