У меня есть этот фрагмент кода (взят из этого вопроса):
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
. В этом контексте, что делает эта команда?
Изменить: Я ценю все дальнейшие комментарии, но вопрос был дан ответ много раз. Спасибо, в любом случае!
10 ответов
!
инвертирует значение и выдает противоположное логическое значение:
!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 оператора, !
и --
!--x
Итак, --
уменьшает x на 1, затем !
возвращает true, если x теперь равно 0 (или NaN ...), и false, если это не так. Вы могли бы прочитать эту идиому что-то вроде «мы уменьшаем х и если это делает его ноль ...»
Если вы хотите сделать его более читабельным, вы можете:
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>
!
является оператором JavaScript НЕ.
--
является оператором перед декрементом. Так,
x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
// which makes the condition to be true
Это стенография.
!
"не".
--
уменьшает значение.
Поэтому !--
проверяет, является ли значение, полученное в результате отрицания результата уменьшения значения, ложным.
Попробуй это:
var x = 2;
console.log(!--x);
console.log(!--x);
Первая ложь, поскольку значение x равно 1, вторая - истина, поскольку значение x равно 0.
Примечание: !x--
сначала проверит, является ли x ложным, а затем уменьшит его.
В ряде ответов описывается что делает эта команда, но не почему здесь это делается именно так.
Я из мира Си и читаю !--pending
как «обратный отсчет pending
и проверяю, равен ли он нулю», не задумываясь об этом. Это идиома, которую, я думаю, должны знать программисты на похожих языках.
Функция использует readdir
для получения списка файлов и подкаталогов, которые я буду называть «записи».
Переменная pending
отслеживает, сколько из них осталось обработать. Он начинается с длины списка и отсчитывается до нуля при обработке каждой записи.
Эти записи могут быть обработаны не по порядку, поэтому необходимо использовать обратный отсчет, а не просто цикл. Когда все записи обработаны, вызывается обратный вызов done
для уведомления исходного абонента об этом факте.
В первом вызове done
добавляется return
не потому, что мы хотим вернуть значение, а просто для того, чтобы функция перестала выполняться в этой точке. Это был бы более чистый код, чтобы отбросить return
и поместить альтернативу в else
.
Это не специальный оператор, это два стандартных оператора один за другим:
- Префиксное декремент (
--
) - Логическое нет (
!
)
Это приводит к уменьшению pending
, а затем проверению на нулевое значение.
Настоящей проблемой здесь является отсутствие пробела между двумя операторами !
и --
.
Я не знаю, почему люди думают, что после оператора !
нельзя использовать пробел. Я думаю, что это происходит из-за жесткого применения механических правил пробела вместо здравого смысла. Почти все стандарты кодирования, которые я видел, запрещают пробелы после всех унарных операторов, но почему?
Если когда-либо был случай, когда вам явно нужно это место, это один из них.
Рассмотрим этот фрагмент кода:
if (!--pending)
done(null, results);
Мало того, что !
и --
смешиваются вместе, у вас есть (
также и их. Неудивительно, что сложно сказать, с чем это связано.
Чуть больше пробелов делает код намного более понятным:
if( ! --pending )
done( null, results );
Конечно, если вы привыкли к механическим правилам, таким как «без пробела внутри паренсов» и «без пробела после унарного оператора», это может показаться немного чуждым.
Но посмотрите, как лишние пробелы группируют и разделяют различные части выражения и выражения if
: у вас есть --pending
, поэтому --
явно является своим собственным оператором и тесно связан в pending
. (Он уменьшает pending
и возвращает уменьшенный результат.) Затем вы отделили !
от этого, так что это, очевидно, отдельный оператор, сводящий на нет результат. Наконец, у вас есть if(
и )
, окружающие все выражение, чтобы сделать его if
оператором.
И да, я удалил пробел между if
и (
, потому что (
принадлежит к if
. Этот (
не является частью какого-либо синтаксиса (!--
, как кажется в оригинале, (
if является частью синтаксиса самого оператора if
.
Пробелы здесь служат для передачи значения значения вместо того, чтобы следовать некоторому стандарту механического кодирования.
if(!--pending)
Средства
if(0 == --pending)
Средства
pending = pending - 1;
if(0 == pending)
Он просто уменьшается pending
на единицу и получает свое логическое дополнение (отрицание). Логическим дополнением любого числа, отличного от 0, является false
, для 0 - true
.
За оператором not следует пре-декремент на месте.
Так что если pending
было целым числом со значением 1:
val = 1;
--val; // val is 0 here
!val // evaluates to true
Похожие вопросы
Связанные вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.