¿Qué hace "!-- "¿en JavaScript?


Tengo este fragmento de código (tomado de esta pregunta):

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);
                }
            });
        });
    });
};

Estoy tratando de seguirlo, y creo que entiendo todo excepto cerca del final donde dice !--pending. En este contexto, ¿qué hace ese comando?

Editar: Aprecio todos los comentarios posteriores, pero la pregunta ha sido respondida muchas veces. Gracias de todos modos!

Author: Community, 2015-12-17

10 answers

! invierte un valor, y te da el booleano opuesto:

!true == false
!false == true
!1 == false
!0 == true

--[value] resta uno (1) de un número, y luego devuelve ese número para trabajar con:

var a = 1, b = 2;
--a == 0
--b == 1

Entonces, !--pending resta uno de pending, y luego devuelve el opuesto de su valor truthy/falsy (sea o no 0).

pending = 2; !--pending == false 
pending = 1; !--pending == true
pending = 0; !--pending == false

Y sí, sigue el ProTip. Este puede ser un lenguaje común en otros lenguajes de programación, pero para la mayoría de la programación JavaScript declarativa esto parece bastante extraño.

 531
Author: TbWill4321,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-18 18:29:31

Ese no es un operador especial, son 2 operadores estándar uno tras otro:

  1. Un decremento de prefijo(--)
  2. Un no lógico (!)

Esto hace que pending se decremente y luego se pruebe para ver si es cero.

 148
Author: Amit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-22 20:18:25

Un número de respuestas describe qué hace este comando, pero no por qué se hace así aquí.

Vengo del mundo C, y leo !--pending como "cuenta atrás pending y compruebo si es cero" sin pensar realmente en ello. Es un idioma que creo que los programadores en lenguajes similares deberían conocer.

La función utiliza readdir para obtener una lista de archivos y subdirectorios, que llamaré colectivamente "entradas".

La variable pending realiza un seguimiento de cuántos de ellos quedan por procesar. Comienza como la longitud de la lista, y cuenta hacia abajo hacia cero a medida que se procesa cada entrada.

Estas entradas pueden procesarse fuera de orden, por lo que es necesario contar hacia abajo en lugar de simplemente usar un bucle simple. Cuando todas las entradas han sido procesadas, se llama a la devolución de llamada done para notificar al llamante original de este hecho.

En la primera llamada a done se antepone con return, no porque queramos devolver un valor, sino simplemente hacer que la función deje de ejecutarse en ese punto. Habría sido un código más limpio soltar el return y poner la alternativa en un else.

 108
Author: Stig Hemmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-17 09:34:01

Es una abreviatura.

! es "no".

-- disminuye un valor.

Así que !-- comprueba si el valor obtenido al negar el resultado de decrementar un valor es false.

Prueba esto:

var x = 2;
console.log(!--x);
console.log(!--x);

El primero es false, ya que el valor de x es 1, el segundo es true, ya que el valor de x es 0.

Nota al margen: !x-- verificaría si x es false primero, y luego lo decrementaría.

 35
Author: Lucas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-16 23:39:10

! es el operador JavaScript NO

-- es un operador pre-decremento. Así,

x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
          // which makes the condition to be true
 30
Author: Sterling Archer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-22 22:46:25
if(!--pending)

Significa

if(0 == --pending)

Significa

pending = pending - 1;
if(0 == pending)
 23
Author: james turner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-11 21:41:43

Es el operador not seguido por el pre-decrementador in situ.

Así que si pending era un entero con un valor de 1:

val = 1;
--val; // val is 0 here
!val // evaluates to true
 13
Author: Brendan Abel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-17 12:46:55

Explicación

Se trata de 2 operadores, a ! y a --

!--x 

Por lo tanto, este detrimentos x por 1, y comprueba si es un booleano.

Si quieres hacerlo más legible, puedes:

var x = 1
x = x - 1   
if(!x){ //=> true
    console.log("I understand `!--` now!") 
}
x //=> 0

Pruébalo:

/* 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 (Probar el código)

 12
Author: Ben Aubin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-14 14:52:26

Simplemente disminuye pending por uno y obtiene su complemento lógico (negación). El complemento lógico de cualquier número diferente a 0 es false, para 0 es true.

 11
Author: MinusFour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-17 03:55:16

El verdadero problema aquí es la falta de un espacio entre los dos operadores ! y --.

No se por qué la gente se mete en la cabeza que nunca se puede usar un espacio después del operador !. Creo que proviene de la aplicación rígida de reglas mecánicas de espacios en blanco en lugar de sentido común. Casi todos los estándares de codificación que he visto prohíben los espacios después de todos los operadores unarios, pero ¿por qué?

Si alguna vez hubo un caso en el que claramente necesita ese espacio, esto es una.

Considere este bit de código:

if (!--pending)
    done(null, results);

No solo están ! y -- aplastados juntos, también tienes que ( aplastado contra ellos. No es de extrañar que sea difícil saber qué está conectado con qué.

Un poco más de espacio en blanco hace que el código sea mucho más claro:

if( ! --pending )
    done( null, results );

Claro, si estás acostumbrado a reglas mecánicas como "sin espacio dentro de paréntesis" y "sin espacio después de un operador único", esto puede parecer un poco extraño.

Pero mira cómo los grupos de espacios en blanco extra y separa las diversas partes de la declaración y expresión if: Tienes --pending, por lo que el -- es claramente su propio operador y está estrechamente vinculado a pending. (Decrementa pending y devuelve el resultado decrementado.) Entonces tienes el ! separado de eso por lo que es obviamente un operador distinto, negando el resultado. Finalmente, tienes if( y ) rodeando toda la expresión para convertirla en una declaración if.

Y sí, eliminé el espacio entre if y (, porque el ( pertenece al if. Esta ( no es parte de algún tipo de sintaxis (!-- como parece estar en el original, la ( if parte de la sintaxis de la propia instrucción if.

El espacio en blanco aquí sirve para comunicar el significado , en lugar de seguir algún estándar de codificación mecánica.

 8
Author: Michael Geary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-19 10:03:46