3

Came across the following on someone's site and I'm curious to understand the shortcut applied here. I simplified the variables for demo purposes.

 function(){
      _imaboolean || ($element.removeClass("hidden").addClass("visible"), this.imaboolean = !0)
 }

Same thing with

this._imaboolean && ($element.removeClass("visible").addClass("hidden"), this._imaboolean = !1)
cusejuice
  • 10,285
  • 26
  • 90
  • 145

5 Answers5

6

That is some awful "clever" code, however, let's decompose it!

_imaboolean || ($element.removeClass("hidden").addClass("visible"), this.imaboolean = !0)

First, let's replace all the expressions with placeholders (note these expressions are not pure and have side-effects):

a || (b, c)

Note that || is short-circuiting such that the right expression - (b, c) - will only be evaluated if a evaluates to a false-y value.

So, let's assume that a evaluates to a false-y value, then (b, c) is evaluated. In this case the , operator separates sub-expressions; all the sub-expressions are evaluated in order. The result of the expression is the result of the last sub-expression.

This means it is roughly equivalent to (although there is no function or binding context and the result is thrown out anyway):

(function () { b; return c })()

Did that make sense? No, of course not!

Write it like you mean it:

if (!_imaboolean) {
  $element.removeClass("hidden").addClass("visible");
  this.imaboolean = true; // get rid of !0 too
}
user2246674
  • 7,621
  • 25
  • 28
2

This code can be inflated to:

function() {
    if (!this.imaboolean) {
        $element.removeClass("hidden").addClass("visible");
        this.imaboolean = true;
    }
}

The || is used as a short circuit, if imaboolean is true it will break out, however if it's false it will execute the remaining portion of the expression. !0 is a minified way of saying true (because 0 evaluates to false in a boolean expression).

Brandon Buck
  • 7,177
  • 2
  • 30
  • 51
  • why `!0`, `1` would be a more minified and more straighforward way for true – gbtimmon May 07 '13 at 19:35
  • 1
    @gbitmmon Because `1` is not a boolean expression and therefore evaluates to `1` when `!0` evaluates to `false` - a boolean value. That is why. – Brandon Buck May 07 '13 at 19:41
  • @gbtimmon `!0 !== 1; 1 !== true; !0 === true` - that is, 1 is not a direct replacement for !0. The previous comment contains an error (it should have been "!0 evaluates to true"), but had the idea correct. While truth-y/false-y *usually* works as intended, there are subtle differences - consider jQuery.extend where the first parameter can be an object or a boolean. – user2246674 May 07 '13 at 19:49
  • @user2246674 I don't buy it. `1` is just as truthy and `0` is falsey. Try `1||alert('test');` and see what happens. `1` is considered true there. And (!0 == 1) doesnt matter. There is an implict cast to boolean in the `||` operator so what you are concerned with is `toBoolean(!0) === toBoolean(1)` which is always true. – gbtimmon May 07 '13 at 19:50
  • @gbtimmon Which is why I used `!==` and `===` explicitly to discuss the nuance. – user2246674 May 07 '13 at 19:52
  • @gbtimmon I did not say that it's `!0` is a shorthand for a "truthy" value, I said it's shorthand for `true`. `!0` is a standard minification for the hardcoded `true`. Try something like `one = true;` and compile with the closure compiler on "Simple" you'll get `one=!0`. – Brandon Buck May 07 '13 at 19:59
1

I believe it is short for

 function(){
      if( ! _imaboolean){
         $element.removeClass("hidden").addClass("visible");
         this.imaboolean = true; 
     }
 }

Its also generally terrible coding in my opinion and should not be copied.

gbtimmon
  • 4,238
  • 1
  • 21
  • 36
  • 1
    I wouldn't say it's terrible, it looks minified. In which case the source is probably not written that way. – Brandon Buck May 07 '13 at 19:34
  • @izuriel it doesn't look minified... This is not how minified code look. – PSL May 07 '13 at 19:34
  • 1
    Even if it isn't minified, "terrible" is a stretch. "Harder to maintain", maybe, but "terrible"? Nah. It isn't `eval`. – Chris Baker May 07 '13 at 19:35
  • I'm of the school that hard to maintain == terrible, but like i said, thats my opinion. – gbtimmon May 07 '13 at 19:37
  • @gbtimmon Not sure what site it was scrapped from but it was pulled from a site and modified for demo purposes (as the asker stated). Other than that, I've seen this done commonly when a more complex minification process is used like the Closure Compiler. But I was just making the statement to provide a secondary argument against the code being "terrible" which it definitely is not if it's been minified. – Brandon Buck May 07 '13 at 19:39
  • If it minified, why is the var name still _imaboolean. Var shorting is the most effective minification and the easiest. Whay refactor code but not refactor var names ?!?!. That what leads me to believe its not minified. – gbtimmon May 07 '13 at 19:43
  • The key point of was that the person asking the question has already modified the source for demo purposes. You're not looking at the original, you're looking at a modified sample. Why would someone name their boolean value `imaboolean` - that's extremely helpful and readable code. – Brandon Buck May 07 '13 at 20:00
0

It's a short-circuit evaluation where the second part will only be evaluated if the first part fails.

Brian Stephens
  • 5,161
  • 19
  • 25
0
function(){
      _imaboolean || ($element.removeClass("hidden").addClass("visible"), this.imaboolean = !0)
 }

Let's break this down. First we see the || operator, so we have (statement) || (anotherStatement). The way || works is that it evaluates the first statement. If that evaluates to true, it short-circuits and does not evaluate the second statement. The first statement is just _imaboolean. If that's a truthy value (i.e., not 0 or false or undefined...), then we stop right there and don't go to the second statement.

The second statement is

($element.removeClass("hidden").addClass("visible"), this.imaboolean = !0)

Again, there's two statements, separated by a comma. The comma operator evaluates BOTH statements, and returns the last one. So it evaluates $element.removeClass("hidden").addClass("visible") (which sets some classes on $element), and then it evaluates this.imaboolean = !0 (which sets this.imaboolean to a truthy value). The next time this function is run, it will short circuit due to the || operator.

Colin DeClue
  • 2,194
  • 3
  • 26
  • 47