views:

68

answers:

6

Using a watermark plugin for jQuery, I'm attempting to jslint and minimize the functions but I've come across syntax I have never seen before wherein there are expressions where there really ought to be an assignment or function call:

(function($) {

    $.fn.watermark = function(css, text) {

        return this.each(function() {

            var i = $(this), w;

            i.focus(function() {
                w && !(w=0) && i.removeClass(css).data('w',0).val('');
            })
                .blur(function() {
                    !i.val() && (w=1) && i.addClass(css).data('w',1).val(text);
                })
                .closest('form').submit(function() {
                    w && i.val('');
                });

            i.blur();
        });
    };

    $.fn.removeWatermark = function() {

        return this.each(function() {

            $(this).data('w') && $(this).val('');
        });
    };
})(jQuery);

I'm specifically interested in the following lines:

w && !(w=0) && i.removeClass(css).data('w',0).val('');

and

!i.val() && (w=1) && i.addClass(css).data('w',1).val(text);

Can someone explain this shorthand and rewrite these functions in such a way that I could compare them to better to understand the shorthand myself?

Thank you.

A: 

&& is And. It's for comparison / compound conditional statements. It requires that both conditions in an if statement be true. I do not think there is another way to rewrite it - that is the syntax for And.

g.d.d.c
A: 

With respect to:

w && !(w=0) && i.removeClass(css).data('w',0).val('');

the code:

!(w=0) && i.removeClass(css).data('w',0).val('');

will only execute if

w

is truthy.

on_conversion
+1  A: 

Let's break each of the statements you're asking about down to their components:

w && !(w=0) && i.removeClass(css).data('w',0).val('');
  • w - Is w "true"? (checking for != 0 in this case)
  • !(w=0) - Set w to 0, take the opposite of the result so the && chain continues
  • i.removeClass(css).data('w',0).val('') - Remove the class, set the data to 0 clear the value.

!i.val() && (w=1) && i.addClass(css).data('w',1).val(text);
  • !i.val() - Is the input empty?
  • (w=1) - Set w to 1
  • i.addClass(css).data('w',1).val(text); - Add the class, set the data to 1 and set the text to whatever the watermark text is.

Both of these are just statements to really cut down on code, certainly at the expense of readability. If you're looking at a de-minified version this is very common, if you're not and this is the original, chase the author with a salad fork, the original should be more more readable than this IMO, though it's just fine for a minified version.

Nick Craver
Not to mention single-letter local variables.
BoltClock
@BoltClock's - I'm *betting* that's a result of minfication though, all of it looks like that. If you're using Chrome I recommend https://chrome.google.com/extensions/detail/nipdlgebaanapcphbcidpmmmkcecpkhg for sanity :)
Nick Craver
@Nick: *Why am I not dead yet?!*
BoltClock
bobince
@bobince - Agreed, I'd much prefer a readable version over this, though the minifiers will do whatever the hell they want.
Nick Craver
A: 

These can be rewritten as:

// w && !(w=0) && i.removeClass(css).data('w',0).val('');
if (w) {
    if (!(w=0)) {
        i.removeClass(css).data('w',0).val('');
    }
}

//!i.val() && (w=1) && i.addClass(css).data('w',1).val(text);
if (!i.val()) {
    if (w=1) {
        i.addClass(css).data('w',1).val(text);
    }
}

Using && like this is just a shorthand for using nested ifs. It's advantages being:

  1. Uses marginally fewer characters than the exploded nested ifs, decreasing the payload that's delivered to the browser.
  2. Can be faster to read for the trained eye.

Though, I must say that the above examples are an abuse of this shorthand because the conditionals used are fairly complex. I only revert to this shorthand when I need to check a chain of simple things like in the following example:

function log(s) {
    window.console && console.log && console.log(s);
}
Ates Goral
+1  A: 

&& can be used as a "guard." Basically it means stop evaluating the expression if one of the operands returns a "falsy" value.

Negating an expression will convert it to a boolean value. Specifically one that is a negation of the expression depending on whether it's 'truthy' or 'falsy'.

w && !(w=0) && i.removeClass(css).data('w',0).val('');

Basically says:

w is "truthy" (defined, true, a string, etc.)
AND set w to zero + convert the expression to true (because (w=0) would evaluate to 0, which is falsy)
AND evaluate i.removeClass(css).data('w',0).val('')
CD Sanchez
A: 

Using

w && !(w=0) && i.removeClass(css).data('w',0).val('');

for this explanation, it allows you to string multiple commands together while ensuring that each is true.

This could also be represented by:

if (w && w != 0) {
    i.removeClass(css).data('w',0).val('');
}

It first makes sure w evaluates to true, and if it is, it checks if w=0 is not true (w != 0). If this is also true, then it goes on to the actual command.

This is common shorthand in a lot of languages that use lazy evaluation: If the next evaluation is put in with and (&&) then the following commands will not be executed if it returns false. This is useful in the sort of situations where you only want to perform an action on something if the previous statement returns true, like:

if (object != null && object.property == true)

to make sure object isn't null before using it, otherwise you would be accessing a null pointer.

Slokun