I was looking through a jQuery smooth-scrolling tutorial, and trying to figure out how it worked, when I hit this line of code:
$target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
I can't figure out what it does. It looks like the guy is assigning a string to a variable, but it also kinda looks like he's testing that variable. And I don't understand the use of && and || here. Can anybody explain this?
Thanks!
EDIT: Wow! What a response! This is taking a bit for me to understand, though - I will have to print this out or something and work on it. Once I understand what's going on, I'll be able to pick the answer that helped me the most. In particular, this bit:
if ($target.length && $target) {
$target = $target;
is stymying me. How does the program know to assign $target to $target? Does the operation assign $target to the first reference to itself (the left side of the equals sign), or to the second reference to itself (the right side, after the &&)?
I was looking through a jQuery smooth-scrolling tutorial, and trying to figure out how it worked, when I hit this line of code:
$target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
I can't figure out what it does. It looks like the guy is assigning a string to a variable, but it also kinda looks like he's testing that variable. And I don't understand the use of && and || here. Can anybody explain this?
Thanks!
EDIT: Wow! What a response! This is taking a bit for me to understand, though - I will have to print this out or something and work on it. Once I understand what's going on, I'll be able to pick the answer that helped me the most. In particular, this bit:
if ($target.length && $target) {
$target = $target;
is stymying me. How does the program know to assign $target to $target? Does the operation assign $target to the first reference to itself (the left side of the equals sign), or to the second reference to itself (the right side, after the &&)?
Share Improve this question edited Oct 1, 2011 at 12:35 StormShadow asked Sep 26, 2011 at 5:57 StormShadowStormShadow 1,6274 gold badges26 silver badges34 bronze badges 5- 1 I've already upvoted what I thought was the best answer, but there's also a problem with his logic. You want to check if $target is not NULL before checking $target.length. The expression would actually be better expressed as a ternary operation. – Gopherkhan Commented Sep 27, 2011 at 3:10
-
@Gopherkhan I get the feeling
$target
is guaranteed to be a jQuery object – Phil Commented Sep 27, 2011 at 5:46 - updated ment If it's guaranteed to be an jquery object, then the ternary option makes even more sense. It's more concise and readable to say $target = $target.length ? $target : $('[name=' + this.hash.slice(1) +']'); for this case. And since $foo is still a valid name in raw js, if it's not guaranteed to be a jquery object, the potential for error is there. Better to be defensive, I'd say. – Gopherkhan Commented Sep 27, 2011 at 23:21
-
1
@StormShadow To explain it using simple words, the program checks if ((
$target.length
is not [undefined
,null
, any falsy value] AND$target.length > 0
) AND ($target
is not [undefined
,null
, any falsy value])) THEN (assign$target
to itself(the already existing reference of$target
)) ELSE (assign$target
to$('[name=' + this.hash.slice(1) +']')
) – Narendra Yadala Commented Oct 12, 2011 at 5:12 - Thanks Narendra - that really clarified it for me. – StormShadow Commented Oct 13, 2011 at 1:53
4 Answers
Reset to default 8It is a cryptic(or elegant?) version of the equivalent ternary operator
$target = ($target.length && $target) ? $target : $('[name=' + this.hash.slice(1) +']');
This ternary and the original short circuit expression will return exactly same values if the evaluation of $target does not change the value of $target. But if the evaluation of $target changes the value of $target then SCE and ternary returns different values e.g.
var a = 1; b = 2; c = 3; a && ++b || c returns 3; //resetting b b = 2 a && ++b ? ++b : c returns 4;
If the evaluation of $target changes the value of $target then the equivalent ternary operator for the SCE $target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
would be the following
$target = ($result= ($target.length && $target)) ? $result : $('[name=' + this.hash.slice(1) +']');
It's testing $target
(which I assume is a jQuery object) for elements and if empty, assigning a default value.
See Logical Operators for a detailed explanation.
Update
To explain (in case you don't feel like reading the MDN docs), JavaScript logical parison operators work left-to-right.
expr1 && expr2
This will return expr1
if it can be converted to false
; otherwise, returns expr2
expr1 || expr2
This will return expr1
if it can be converted to true
; otherwise, returns expr2
To break down the line in question, think of it this way
$target = ($target.length && $target) || $('[name=' + this.hash.slice(1) +']');
Looking at the first operation...
$target.length && $target
This will return $target.length
if $target.length
can be converted to false
(ie 0
), otherwise it will return $target
.
The second operation looks like this...
(operation1) || $('[name=' + this.hash.slice(1) +']')
If the result of the operation1
can be converted to true
(ie $target
), then it will be returned, otherwise $('[name=' + this.hash.slice(1) +']')
.
This is called Short Circuit evaluation and its not equivalent of ternary operator.
and your peace of code equivalent is following:
if ($target.length && $target) {
$target = $target;
}
else {
$target = $('[name=' + this.hash.slice(1) +']');
}
In JavaScript and most of other loosely-typed languages which have more than the two truth-values True and False, the value returned is based on last value.
a && b
will return a if it false, else will return b.
a || b
will return a if true, else b.
to better understand last value look at the following examples:
var a = true;
var b = false;
var c = 5;
var d = 0;
return a && b; //returns false
return a && c; //returns 5
return b && c; //returns false
return c && b; //returns false
return c && a; //returns true;
return d && b; //returns 0;
return b && d; //returns false;
return a || b; //returns true
return a || c; //returns true
return b || c; //returns 5
return c || b; //returns 5
return c || a; //returns 5;
return d || b; //returns false;
return b || d; //returns 0;
Update:
Ternary operator:
(condition)?(evaluate if condition was true):(evaluate if condition was false)
Short Circuit Evaluation:
(evaluate this, if true go ahead else return this) && (evaluate this, if true go ahead else return this)
You can clearly see that there is a condition
for ternary operator while in SCE the evaluation of value itself is the condition.
$target = $target.length && $target || $('[name=' + this.hash.slice(1) +']');
In javascript you can make inline parisons when assigning a variable so the example you is the equivalent to
if($target.length && $target)
$target = $target;
else
$target = $('[name=' + this.hash.slice(1) +']');
for more examples, see http://www.w3schools./JS/js_parisons.asp
for example:
var x= y > 4 ?value1:value2
Witch means that if condition is true (y is greater than 4), x will be assigned value1 otherwise it will be assigned value2