J'ai ce morceau de code (pris de cette 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);
}
});
});
});
};
J'essaie de le suivre et je pense tout comprendre sauf la fin où il est dit !--pending
. Dans ce contexte, que fait cette commande?
Edit: J'apprécie tous les autres commentaires, mais la question a été répondue à plusieurs reprises. Merci quand même!
!
inverse une valeur et vous donne le booléen opposé:
!true == false
!false == true
!1 == false
!0 == true
--[value]
soustrait un (1) à un nombre, puis renvoie ce nombre avec lequel travailler:
var a = 1, b = 2;
--a == 0
--b == 1
Ainsi, !--pending
soustrait un élément de l'attente, puis renvoie l'opposé de sa valeur vérité/fausseté (que ce soit ou non 0
).
pending = 2; !--pending == false
pending = 1; !--pending == true
pending = 0; !--pending == false
Et oui, suivez les conseils. Cela peut être un langage courant dans d’autres langages de programmation, mais pour la plupart des programmes JavaScript déclaratifs, cela semble assez étrange.
Ce n'est pas un opérateur spécial, c'est 2 opérateurs standard l'un après l'autre:
--
)!
)Cela provoque la décrémentation de pending
, puis son test pour voir s'il est nul.
Un certain nombre de réponses décrit quoi cette commande le fait, mais pas pourquoi c'est ce qui se passe ici.
Je viens du monde C et je lis !--pending
comme "décompte pending
et vérifie s'il est égal à zéro" sans vraiment y penser. C’est un idiome que les programmeurs de langages similaires devraient connaître.
La fonction utilise readdir
pour obtenir une liste de fichiers et de sous-répertoires, que j'appellerai collectivement "entrées".
La variable pending
garde une trace du nombre de ces restes à traiter. Il commence par la longueur de la liste et compte à rebours vers zéro à mesure que chaque entrée est traitée.
Ces entrées peuvent être traitées dans le désordre, c'est pourquoi il est nécessaire de compter à rebours plutôt que d'utiliser une simple boucle. Lorsque toutes les entrées ont été traitées, le rappel done
est appelé pour informer l'appelant initial de ce fait.
Dans le premier appel à done
est précédé de return
, non pas parce que nous voulons renvoyer une valeur, mais simplement pour que la fonction cesse de s'exécuter à ce moment-là. Il aurait été plus propre de laisser tomber le return
et de placer l’alternative dans un else
.
C'est un raccourci.
!
n'est "pas".
--
décrémente une valeur.
Donc, !--
vérifie si la valeur obtenue en annulant le résultat de la décrémentation d'une valeur est fausse.
Essaye ça:
var x = 2;
console.log(!--x);
console.log(!--x);
Le premier est faux, puisque la valeur de x est 1, le second est vrai, puisque la valeur de x est 0.
Note latérale: !x--
vérifierait si x est faux en premier, puis le décrémente.
!
est l'opérateur JavaScript NOT
--
est un opérateur de pré-décrémentation. Alors,
x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
// which makes the condition to be true
if(!--pending)
veux dire
if(0 == --pending)
veux dire
pending = pending - 1;
if(0 == pending)
C'est l'opérateur not suivi du pré-décrémenteur en place.
Donc, si pending
était un entier valant 1:
val = 1;
--val; // val is 0 here
!val // evaluates to true
Ceci est 2 opérateurs, un !
et un --
!--x
Donc, cela nuit x par 1 et vérifie si c'est un booléen.
Si vous voulez le rendre plus lisible, vous pouvez:
var x = 1
x = x - 1
if(!x){ //=> true
console.log("I understand `!--` now!")
}
x //=> 0
/* 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>
Elle diminue simplement pending
de un et obtient son complément logique (négation). Le complément logique de tout nombre différent de 0 est false
, pour 0, il est true
.
Le vrai problème ici est le manque d'espace entre les deux opérateurs !
et --
.
Je ne sais pas pourquoi les gens comprennent qu'il est impossible d'utiliser un espace après l'opérateur !
. Je pense que cela vient d'une application rigide de règles mécaniques d'espaces au lieu du bon sens. Presque toutes les normes de codage que j'ai vues interdisent les espaces après tous les opérateurs unaires, mais pourquoi?
S'il y a déjà eu un cas où vous avez clairement besoin cet espace, c'est le cas.
Considérez ce morceau de code:
if (!--pending)
done(null, results);
Non seulement !
et --
sont-ils écrasés, vous avez également (
critiqués. Pas étonnant qu'il soit difficile de dire ce qui est connecté à quoi.
Un peu plus d'espaces rend le code beaucoup plus clair:
if( ! --pending )
done( null, results );
Bien sûr, si vous êtes habitué à des règles mécaniques telles que "pas d'espace à l'intérieur" et "pas d'espace après un opérateur unaire", cela peut sembler un peu étranger.
Mais regardez comment les espaces blancs supplémentaires séparent les différentes parties de l'instruction et de l'expression if
: vous avez --pending
, le --
est donc clairement son propre opérateur et est étroitement lié. à pending
. (Il décrémente pending
et renvoie le résultat décrémenté.) Ensuite, vous avez le !
séparé de celui-ci; il est donc évident qu'un opérateur distinct annule le résultat. Enfin, vous avez if(
et )
entourant l'expression entière pour en faire une instruction if
.
Et oui, j'ai supprimé l'espace entre if
et (
, car le (
appartient au if
. Ce (
ne fait pas partie d'une sorte de syntaxe de (!--
telle qu'elle apparaît dans l'original, le (
s'il fait partie de la syntaxe de l'instruction if
elle-même.
Les espaces servent ici à communiquer le signification, au lieu de suivre certaines normes de codage mécanique.