0

I'm trying to write a function I can use to test all for falsy values, keeping it concise since it will be run quite often serverside.

function is_falsy(val){
   val = eval(String(val).toLowerCase());
   return !!val;
}

I wonder if there's any way it could be done shorter, or what the possible negative implications of using eval() might be. JSBIN tells me it is "evil".

JSBIN

15
  • 4
    Explain the original task. It's not clear what you want to achieve with this function Commented Jan 7, 2014 at 3:40
  • 4
    I'm having a hard time following what this function would do, but that may be me Commented Jan 7, 2014 at 3:40
  • 1
    @Pekka 웃: it's 2 of us. PS: he probably wants 'false' to be falsy Commented Jan 7, 2014 at 3:41
  • Please don't do this. Imagine any arbitrary piece of javascript inserted into the middle of your code, then imagine what possible damage it could do. Now you know why eval is evil. Commented Jan 7, 2014 at 3:43
  • 2
    Can you define what values you are regarding as falsy? Your definition seems to differ from the generally accepted one Commented Jan 7, 2014 at 3:45

3 Answers 3

5

Assuming that val is a string that represents a JavaScript literal then we can take advantage of the fact that the only false-y values in JavaScript are:

  • 0 (+ or -)
  • NaN
  • the empty string ('') or ("")
  • null
  • undefined
  • false

Thus, ignoring edge-cases (like 0.0) we could write it like so (a lower case can be performed as in the original code):

function is_falsey_literal (lit) {
  if (['""', "''", "null", "undefined", "false", "0", "NaN"].indexOf(lit) >= 0) {
    return true;
  }
  // Ideally there are more checks on numeric literals such as `-0` or `0.0`.
  return false;
}

If needing to check a full expression then eval may "work" and is likely more practical when compared to writing a full JavaScript-in-JavaScript parser. For instance, in the above, the input string of (void 0) will be "true" although it evaluates to undefined which is definitely not a truth-y value.

Of course, perhaps the original data can be written/consumed such that there is no need for such a construct at all ..

Sign up to request clarification or add additional context in comments.

4 Comments

What do you mean by "JavaScript-in-JavaScript" parser?
@thomas Rewriting eval without using eval :)
But how would you do that?! :D
@thomas By writing a lexer, parser, and evaluator for the relevant portion(s) of the ECMAScript language .. or, doing something like JS.JS: "js.js is a JavaScript interpreter in JavaScript. Instead of trying to create an interpreter from scratch, SpiderMonkey is compiled into LLVM and then emscripten translates the output into JavaScript." :)
2

There should never be any need to treat a string containing false or undefined as falsy. Doing so is inviting false positives (or false negatives) on possibly completely unrelated data.

Imagine what else would be treated as "falsy":

  • !true
  • !1
  • !!true

it's begging for mysterious bugs in your application further down the line.

The program flow should make sure that an undefined value actually arrives at your testing script as a literal undefined, not a string "undefined".

4 Comments

It's just the situation. I didn't design it, and I don't have control over architecture elements farther up the hierarchy.
@Pekka 웃: it's a great combination isn't it: a messy architecture and a messy implementation :-)
@zerkms well, it does happen... :)
@Pekka 웃: not in our wonderworld with bug-free code and unicorns ;-)
1

If you only want to test is falsy, then the below is enough.

function is_falsy(val){
   return !val;
}

If you want to test whether a string is falsy value like 'false', then

function is_falsy(val){
   try {
     return !JSON.parse(String(val).toLowerCase());
   } catch(e) {
     return false;
   }
}

3 Comments

'false' for OPs code acts as a falsy value, while not with yours PS: -1 not mine
JSON.parse(String(val).toLowerCase()) would fail for any string that isn't a valid literal type
I would just enumerate all exception values like user2864740 in their answer did

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.