The first one,
if(value != 'foo') {}
is not only more readable, but is the only one that works how you seem to expect it to.
This means "value does not equal 'foo'".
Your second one,
if(!value == 'foo') {}
means "does the inverted truthiness of value equal 'foo'"
(it casts value into a boolean, and takes the negated version of that)
If, however, you meant to say
if (!(value == 'foo'))
for your second one, then the answer is still the same for which is better: the first one.
There's no reason to expand a statement, making it more confusing, when != already exists.
Look at this demo:
const value1 = "foo";
const value2 = "bar";
console.log("expected", false, true);
console.log("first option", value1 != 'foo', value2 != 'foo');
console.log("second option", !value1 == 'foo', !value2 == 'foo');
console.log("modifed second option", !(value1 == 'foo'), !(value2 == 'foo'));
| test |
"foo" |
"bar" |
| expected |
false |
true |
| first option |
false |
true |
| second option |
false |
false |
| modifed second option |
false |
true |
As you can see, your given second option will always result in false because it's testing if true (if value is empty string) or false (if value is non-empty string) is equal to the string literal foo