问题
I have this piece of code (taken from this question):
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err)
return done(err);
var pending = list.length;
if (!pending)
return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending)
done(null, results);
});
} else {
results.push(file);
if (!--pending)
done(null, results);
}
});
});
});
};
I'm trying to follow it, and I think I understand everything except for near the end where it says !--pending
. In this context, what does that command do?
Edit: I appreciate all the further comments, but the question has been answered many times. Thanks anyway!
回答1:
!
inverts a value, and gives you the opposite boolean:
!true == false
!false == true
!1 == false
!0 == true
--[value]
subtracts one (1) from a number, and then returns that number to be worked with:
var a = 1, b = 2;
--a == 0
--b == 1
So, !--pending
subtracts one from pending, and then returns the opposite of its truthy/falsy value (whether or not it's 0
).
pending = 2; !--pending == false
pending = 1; !--pending == true
pending = 0; !--pending == false
And yes, follow the ProTip. This may be a common idiom in other programming languages, but for most declarative JavaScript programming this looks quite alien.
回答2:
That's not a special operator, it's 2 standard operators one after the other:
- A prefix decrement (
--
) - A logical not (
!
)
This causes pending
to be decremented and then tested to see if it's zero.
回答3:
A number of answers describes what this command does, but not why it is done that way here.
I come from the C world, and I read !--pending
as "count down pending
and check if it is zero" without really thinking about it. It is an idiom that I think programmers in similar languages should know.
The function uses readdir
to get a list of files and subdirectories, which I will collectively call "entries".
The variable pending
keeps track of how many of these remains to be processed. It starts out as the length of the list, and counts downward towards zero as each entry is processed.
These entries may be processed out of order, which is why it is necessary to count down rather than just using a simple loop. When all the entries have been processed the callback done
is called to notify the original caller of this fact.
In the first call to done
is prepended with return
, not because we want to return a value, but simply to make the function stop executing at that point. It would have been cleaner code to drop the return
and put the alternative in an else
.
回答4:
It's a shorthand.
!
is "not".
--
decrements a value.
So !--
checks if the value obtained from negating the result of decrementing a value is false.
Try this:
var x = 2;
console.log(!--x);
console.log(!--x);
The first is false, since the value of x is 1, the second is true, since the value of x is 0.
Side note:
!x--
would check if x is false first, and then decrement it.
回答5:
!
is the JavaScript NOT operator
--
is a pre-decrement operator. So,
x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
// which makes the condition to be true
回答6:
if(!--pending)
means
if(0 == --pending)
means
pending = pending - 1;
if(0 == pending)
回答7:
It's the not operator followed by the in-place pre-decrementer.
So if pending
was an integer with a value of 1:
val = 1;
--val; // val is 0 here
!val // evaluates to true
回答8:
It merely decreases pending
by one and obtains its logical complement (negation). The logical complement of any number different than 0 is false
, for 0 it is true
.
回答9:
Explanation
This is 2 operators, a !
and a --
!--x
So, the --
decrements x by 1, then the !
returns true if x is now 0 (or NaN...), false if it isn't. You might read this idiom something like "we decrement x and if that makes it zero..."
If you wanted to make it more readable, you can:
var x = 1
x = x - 1
if(!x){ //=> true
console.log("I understand `!--` now!")
}
x //=> 0
Try it out:
/* This is an example of the above, you can read this, but it is not needed for !-- */function interactive(a){$("span.code").keydown(function(e){if(13==(e.keyCode||e.which)){var t=$(this);t.clone().html("code").insertAfter(t.next().next()).show().focus().after(template.clone().removeClass("result-template").show()).next().after("<br>"),interactive(),e.preventDefault()}}).keyup(function(e){13!=(e.keyCode||e.which)&&run()})}var template=$(".result-template").hide(),code=$("span.code");code.attr("contenteditable","true").each(function(e,t){template.clone().removeClass("result-template").insertAfter(t)}),interactive(),$.fn.reduce=[].reduce;function run(){var b=!1,context={};$("span.code").each(function(){var a=$(this),res=a.next().show().removeClass("error");try{with(context)res.html(b?"":" //=> "+eval(a.text()))}catch(e){b=e,res.html(" Error: "+b.message).addClass("error")}})};run();
/* This is an example of the above, you can read this, but it is not needed for !-- */span.result.error{display:block;color:red}.code{min-width:10px}body{font-family:Helvetica,sans-serif}
<!-- This is an example of the above, you can read this, but it is not needed for `!--` --><span class="result result-template"> //=> unknown </span> <h2>Edit This Code:</h2><code><span class="code">x = 1</span><br><span class="code">!--x</span><br><span class="code"> x </span><br></code> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Fiddle (Try Out Code)
回答10:
The real problem here is the lack of a space between the two operators !
and --
.
I don't know why people get it in their heads that you can't ever use a space after the !
operator. I think it comes from rigid application of mechanical whitespace rules instead of common sense. Just about every coding standard I've seen prohibits spaces after all unary operators, but why?
If there were ever a case where you clearly need that space, this is one.
Consider this bit of code:
if (!--pending)
done(null, results);
Not only are !
and --
mashed together, you've got that (
slammed against them too. No wonder it's hard to tell what is connected to what.
A bit more whitespace makes the code much more clear:
if( ! --pending )
done( null, results );
Sure, if you're used to mechanical rules like "no space inside parens" and "no space after a unary operator", this may seem a bit foreign.
But look at how the extra whitespace groups and separates the various parts of the if
statement and expression: You've got --pending
, so the --
is clearly its own operator and is tied closely to pending
. (It decrements pending
and returns the decremented result.) Then you've got the !
separated from that so it's obviously a distinct operator, negating the result. Finally, you've got if(
and )
surrounding the whole expression to make it an if
statement.
And yes, I removed the space between if
and (
, because the (
belongs to the if
. This (
isn't part of some kind of (!--
syntax as it appears to be in the original, the (
if part of the syntax of the if
statement itself.
The whitespace here serves to communicate the meaning, instead of following some mechanical coding standard.
来源:https://stackoverflow.com/questions/34323527/what-does-do-in-javascript