Can anyone explain what is happening in this bit of Javascript?
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 &&)?
It 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 comparison 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 comparisons 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.com/JS/js_comparisons.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
精彩评论