Что делает "! -" в 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
.
Пробелы здесь служат для передачи значения, вместо того, чтобы следовать стандарту механического кодирования.