Что делает "! -" в JavaScript?

У меня есть этот кусок кода (взятый из этот вопрос):

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

Я пытаюсь следовать за ним, и я думаю, что все понимаю, кроме как в конце, где он говорит !--pending. В этом контексте, что делает эта команда?

Изменить: я ценю все дальнейшие комментарии, но на вопрос был дан ответ много раз. В любом случае, спасибо!

Ответ 1

! инвертирует значение и дает вам противоположное логическое значение:

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

--[value] вычитает один (1) из числа, а затем возвращает это число для работы с:

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

Итак, !--pending вычитает один из ожидающих, а затем возвращает противоположность его правдивому/ложному значению (независимо от того, является ли оно 0).

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

И да, следуйте за ProTip. Это может быть распространенной идиомой на других языках программирования, но для большинства декларативных JavaScript-программирования это выглядит довольно чуждо.

Ответ 2

Это не специальный оператор, это два стандартных оператора один за другим:

  • Атрибут префикса (--)
  • Логическое не (!)

Это приводит к тому, что pending будет уменьшаться, а затем проверяется на отсутствие нуля.

Ответ 3

В нескольких ответах описывается, что делает эта команда, но не почему это делается здесь.

Я родом из мира C, и я читаю !--pending как "count down pending и проверяю, равен ли он нулю", не думая об этом. Это идиома, о которой я думаю, что программисты на подобных языках должны знать.

Функция использует readdir, чтобы получить список файлов и подкаталогов, которые я буду коллективно называть "записями".

Переменная pending отслеживает, сколько из них осталось обработать. Он начинается как длина списка и отсчитывается вниз до нуля, когда обрабатывается каждая запись.

Эти записи могут быть обработаны не по порядку, поэтому необходимо отсчитывать, а не просто использовать простой цикл. Когда все записи обработаны, обратный вызов done вызывается, чтобы уведомить об этом оригинального вызывающего абонента.

В первом вызове done добавляется return, а не потому, что мы хотим вернуть значение, а просто для того, чтобы функция прекратила выполнение в этой точке. Было бы более чистым кодом отказаться от return и поставить альтернативу в else.

Ответ 4

Это сокращенная версия.

! "не".

-- уменьшает значение.

Итак, !-- проверяет, является ли значение, полученное от отрицания результата декремента значения, ложным.

Попробуйте следующее:

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

Первая ложь, так как значение x равно 1, второе - true, так как значение x равно 0.

Боковое примечание: !x-- будет проверять, является ли x первым, а затем уменьшает его.

Ответ 5

! является оператором JavaScript НЕ

-- является предредукционным оператором. Таким образом,

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)

означает

if(0 == --pending)

означает

pending = pending - 1;
if(0 == pending)

Ответ 7

Это не оператор, за которым следует предварительный декремент на месте.

Итак, если pending было целым числом со значением 1:

val = 1;
--val; // val is 0 here
!val // evaluates to true

Ответ 8

Объяснение

Это 2 оператора, a ! и a --

!--x 

Итак, это ухудшает x на 1 и проверяет, является ли оно логическим.

Если вы хотите сделать его более читаемым, вы можете:

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>

Ответ 9

Он просто уменьшает pending на единицу и получает свое логическое дополнение (отрицание). Логическим дополнением любого числа, отличного от 0, является false, для 0 оно true.

Ответ 10

Реальная проблема здесь заключается в отсутствии пробела между двумя операторами ! и --.

Я не знаю, почему люди получают это в своих головах, что вы не можете использовать пробел после оператора !. Я думаю, что это происходит из-за жесткого применения механических правил пробелов вместо здравого смысла. Почти каждый стандарт кодирования, который я видел, запрещает пробелы после всех унарных операторов, но почему?

Если бы вам когда-нибудь понадобилось это пространство, это один.

Рассмотрим этот бит кода:

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

Не только ! и -- выровнены вместе, у вас есть, что ( тоже врезался в них. Неудивительно, что трудно сказать, что связано с чем.

Немного больше пробелов делает код более понятным:

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

Конечно, если вы привыкли к механическим правилам, таким как "нет места внутри парнеров" и "нет места после унарного оператора", это может показаться немного чуждым.

Но посмотрите, как дополнительные пробелы группируются и разделяют различные части оператора if и выражение: у вас есть --pending, поэтому -- явно является его собственным оператором и тесно привязан к pending. (Он уменьшает pending и возвращает уменьшенный результат.) Затем вы отделите ! от этого, чтобы он явно отличался от оператора, отрицая результат. Наконец, у вас есть if( и ), окружающие все выражение, чтобы сделать его выражением if.

И да, я удалил пробел между if и (, потому что ( принадлежит if. Этот ( не является частью какого-либо синтаксиса (!--, который, как представляется, находится в исходной, (, если это часть синтаксиса самого оператора if.

Пробелы здесь служат для передачи значения, вместо того, чтобы следовать стандарту механического кодирования.