The Not-Not Pattern (!!), or bang-bang, is a way in JavaScript to do a type conversion.
!
means NOT. So ...
-
!true
isfalse
-
!false
istrue
-
!0
istrue
-
!1
isfalse
So when converting a value to a boolean, the code inverts it and inverts it again.
Examples
!!false === false
!!true === true
!!0 === false
!!parseInt("foo") === false // NaN is falsy
!!1 === true
!!-1 === true // -1 is truthy
!!(1/0) === true // Infinity is truthy
!!"" === false // empty string is falsy
!!"foo" === true // non-empty string is truthy
!!"false" === true // even if it contains a falsy value
!!window.foo === false // undefined value is falsy
!!undefined === false // undefined primitive is falsy
!!null === false // null is falsy
!!{} === true // an (empty) object is truthy
!![] === true // an (empty) array is truthy
In the Real World
If those examples weren't enough to get you to think about this pattern differently, you should know that this pattern can have some significant and unexpected side-effects.
A codebase I was working in loaded information on images on the page. We had a process that needed to run if an image was returned. The thought behind this code was that it should not run if there was an error.
Six developers and months of time were spent trying to track down a bug. This bug showed up one in every 3,000 times the information on an image was loaded.
The Code
Patience and persistence on the part of an intern revealed a significant side effect.
const image = { name: 'BOB.jpg' };
function checkImage(image) {
if (!!image) {
console.log('image exists');
}
}
checkImage(image);
So, the original code looked as you see above. an image object was passed in and if it exists, the console.log
is run.
Unexpected Side-Effect
Here's where the side-effect came in ...
const image = "ERROR: Authentication Wrong";
function checkImage(image) {
if (!!image) {
console.log('image exists');
}
}
checkImage(image);
With the code above, the intern saw that when an error occurred, the Not-Not Pattern saw the error message at true and it tried to process as if there was an image.
A Solution
The solution wasn't challenging.
We needed a better pattern for checking the image
object. This is one solution; there can be many more.
const image = "ERROR: Authentication Wrong";
function isObject(val) {
if (val === null) { return false;}
return ( (typeof val === 'function') || (typeof val === 'object') );
}
function checkImage(image) {
if (isObject(image) === true) {
console.log('image exists');
}
}
checkImage(image);
With the code above, the console.log
does not run.
Summary
The Not-Not Pattern (!!), or bang-bang, is a way in JavaScript to do a type conversion. This pattern can have some significant and unexpected side-effects.
Because of these side effects I am reluctant to use the pattern in most cases and write code that is longer, with more clarity of purpose, and less potential side-effects.
Top comments (2)
What real anti-pattern in your code is mixing types, and this has nothing to to with
!!
. Your function may receive anObject
, aString
, or anull
, and had no notion of it. Another anti-pattern istypeof
for such cases.This is solved with anything from the Maybe monad to typing your data correctly:
In the real word,
!!
is not needed for other reasons.!!
converts from "falsy" tofalse
, but it has no value by itself, as any JS context expecting a boolean, does it for you:So in your original code
if(image)
is strictly equivalent toif(!!image)
.TS would have helped here a lot.