I was writing a function that takes an argument and returns a truth value.
My initial idea was just return !!value
, but this will fail for '0'
, {}
or []
. I know that '0'
should be true but in my application we are considering it false.
So, my function should return false for:
- Falsey values:
false
,0
,undefined
,null
,''
- Blank values:
{}
,[]
- Special requirement:
'0'
So considering it, I updated code to following to handle
var isTrue = function(value) {
switch (typeof(value)) {
case "string":
return !(value === '0' || value === 'false');
case "number":
case "boolean":
return !!value;
case "object":
return Object.keys(value).length > 0
}
}
console.log(false,isTrue(false))
console.log(true,isTrue(true))
console.log(0,isTrue(0))
console.log(1,isTrue(1))
console.log('0',isTrue('0'))
console.log('1',isTrue('1'))
console.log('test',isTrue('test'))
console.log('Object',isTrue({}))
console.log('Array',isTrue([]))
Now this works fine. It does not include handling for functions
but that is out of scope of current question. My question is, is there a better way to handle the same?
2 Answers 2
I thought it might be faster to:
- first merely evaluate the value "standard" truth with
!!value
- then add conditions for your special requirements (including
'false'
, not cited in your question but present in your code)
This way, it also reduces the code, like this:
var isTrue = function(value) {
return (!!value && value !== '0' && value !== 'false'
&& !!(typeof value !== 'object' || Object.keys(value).length));
}
console.log(false,isTrue(false));
console.log("'false'",isTrue('false'));
console.log(true,isTrue(true));
console.log(0,isTrue(0));
console.log(1,isTrue(1));
console.log("'0'",isTrue('0'));
console.log("'1'",isTrue('1'));
console.log("'test'",isTrue('test'));
console.log('{}',isTrue({}));
console.log('[]',isTrue([]));
console.log('Object',isTrue({a: 1}));
console.log('Array',isTrue([1]));
Now we can observe that it works more than 2 times faster.
Here an execution of the same cases set as above, repeated 100 times:
var isTrue = function(value) {
switch (typeof(value)) {
case "string":
return !(value === '0' || value === 'false');
case "number":
case "boolean":
return !!value;
case "object":
return Object.keys(value).length > 0
}
}
var isTrue_2 = function(value) {
return (!!value && value !== '0' && value !== 'false'
&& !!(typeof value !== 'object' || Object.keys(value).length));
}
var values = [false, 'false', true, 0, 1, '0', '1', 'test', {}, [], {a: 1}, [1]],
times = 100;
console.time('isTrue');
for (var i = 0; i < times; i++) {
for (var value of values) {
isTrue(value);
}
}
console.timeEnd('isTrue');
console.time('isTrue_2');
for (var i = 0; i < times; i++) {
for (var value of values) {
isTrue_2(value);
}
}
console.timeEnd('isTrue_2');
Last point of interest: if you can have some statistics about how much the special requirements appear, you may change the order of the conditions to put the most frequent cases first, so yet improving performance.
Since you have special falsey cases, your checking type by type looks to me as the only option. However, I'd suggest two improvements:
First one is, if the value is boolean you don't need the !!
, as it will only be either True
or False
. Removing the operator would -slightly- improve performance. I'd replace
case "number":
case "boolean":
return !!value;
with
case "number":
return !!value;
case "boolean":
return value;
The second improvement is that the switch
block should have a default
statement, and your case "object"
is a good candidate, so I'd replace
case "object":
return Object.keys(value).length > 0
with
default:
return Object.keys(value).length > 0
-
\$\begingroup\$ The reason why I used free fall through was to reuse
!!value
. This will be correct for both numbers and boolean. Yes 1 extra task is done for boolean, but I guess this is where things become gray. Also, 1 good point is I missed a default value. But I thought not returning would be similar todefault: return false
\$\endgroup\$Rajesh Dixit– Rajesh Dixit2016年10月27日 11:31:34 +00:00Commented Oct 27, 2016 at 11:31 -
\$\begingroup\$ @Rajesh not returning would be like
default: return undefined;
. If you want yourisTrue()
function to return a boolean value, you need to explicitly set thedefault
statement. \$\endgroup\$LostMyGlasses– LostMyGlasses2016年10月27日 11:46:26 +00:00Commented Oct 27, 2016 at 11:46
0
as false and1
as true. But some apps depend on localStorage, so sometimes we get'0'
or'1'
. I also thought to extend its scope as it a generic function, so added functionality forboolean
and boolean as string('true', 'false') andobject/arrays
\$\endgroup\$isMySpecialPropertyTrue
(with "MySpecialProperty" of course a phrase referring to the context you are using it in). \$\endgroup\$