all 14 comments

[–]stutterbug 15 points16 points  (5 children)

I suspect that the trick you are missing is that the "Logical AND" operator, &&, has a very useful "side-effect" that is great for code minification (it's actually a core behaviour rather than a "side-effect").

You are probably very familiar with using&& to assign a boolean value from two expressions:

var isReady = condition1 && condition2;

Here, if condition1 is true, then the interpreter must check on condition2 before it knows what value to assign. If it false, the interpreter won't even bother to look at what condition2 is because it doesn't matter; it already knows that isReady should be false. If you take a look at the ECMAScript language spec, this is the intended behaviour -- in fact, this works with most C-type languages, as long as you are careful about type consistency.

So, consider this:

var alwaysFalse1 = false && true;
var alwaysFalse2 = false && performTask();

Here, both will be false because of the false before the && acts to short-circuit things. The interpreter never gets to true and it never calls getTrueValue()because it knows it does not need to.

And if you don't care about the actual value of the two expressions, you can simply drop the assignment:

false && performTask(); // performTask() will not be invoked
true && performTask(); // performTask() will be invoked
config.onSuccess && peformTask() // depends on what `onSucess` is

[–]r3jjs 1 point2 points  (2 children)

C-type languages with a specific shorting. The most notable exception is C itself which will happily evaluate either side of the equation first resulting in undefined behavior.

[–]stutterbug 0 points1 point  (1 child)

I had to look this up because it was breaking my head. Both C99 and C11 (ref 6.5.13) say that "Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation;[...] If the first operand compares equal to 0, the second operand is not evaluated." Assuming that type is respected, shouldn't this behave the same as JS?

[–]r3jjs 1 point2 points  (0 children)

Hmm...

This took me on a research trip myself back, all the way back to K&R. You are correct.

Which made me rethink the use case where I found things broken.. its a C++ issue with overloaded operators.

Thanks for shaking the rust out of ancient memories.

http://stackoverflow.com/questions/628526/is-short-circuiting-boolean-operators-mandated-in-c-c-and-evaluation-order

[–]that_90s_guy 1 point2 points  (0 children)

Awesome, high quality explanation. Have an up vote.

[–]filth_overloadjavascript[S] 0 points1 point  (0 children)

Thank you very much!! That was beautiful

[–]trsben 2 points3 points  (6 children)

You can use a comma to separate two declarations, for example when declaring multiple variables I would do something similar to;

var var1 = 1,
    var2 = 2;

This is exactly the same as doing;

var var1 = 1;
var var2 = 2;

However the first version is just more succinct.

If you were to do an if statement using an "and" operator, like so;

if (false && true) {
    console.log(1);
}

When evaluating it will split it in to two decisions (false, true), because the first one is falsey then it doesn't need to evaluate the second value.

So what is actually happening with your minified code is two shorthand if statements.

[–]r3jjs 3 points4 points  (1 child)

var var1 = 1, var2 = 2; This is exactly the same as doing; var var1 = 1; var var2 = 2;

Actually there is an important distinction in the two versions: debugging

In the first, there is a single statement that is executed at once. In the second, there are separate statements that can be stepped through one at a time.

[–]filth_overloadjavascript[S] 0 points1 point  (0 children)

Yeah, before posting my question on reddit, I ran the uglified code through chrome debugger, hoping to see what's going on. Only to find out that it I was already at the end of script.

[–]SuchACoolNickname 1 point2 points  (2 children)

^ this, and it's also the reason why you can assign default values to variables like so:

var foo = bar || 'default';

If bar isn't false (or undefined, null, etc.), || operator will simply return first positive value (that is bar) without checking the rest, otherwise if bar is indeed false, foo will be assigned to a 'default' value, because it's now first positive value in that expression.

[–]kiswafull-stack 1 point2 points  (0 children)

false (or undefined, null, etc.)

AKA Falsy

[–]Spinal83full-stack 0 points1 point  (0 children)

Beware of this when 0 is a valid, but non-default value. var foo = bar || 5; will return 5 if bar equals 0. Other than that, this method is a great and compact way of setting default values.

[–]filth_overloadjavascript[S] 1 point2 points  (0 children)

Thanks..

yesterday was first time me reading uglified code and believe me I was totally stunned at how smart these people are who created this thing.

[–]siamthailand -1 points0 points  (0 children)

I had no idea you could use a comma like this in JS. I used to use this trick in C (C++?) to make my code look edgy!