378

我有这段代码(取自这个问题):

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。在这种情况下,该命令有什么作用?

编辑:我感谢所有进一步的评论,但这个问题已经回答了很多次。不管怎么说,还是要谢谢你!

4

10 回答 10

539

!反转一个值,并为您提供相反的布尔值:

!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 编程来说,这看起来很陌生。

于 2015-12-16T22:44:50.810 回答
149

这不是一个特殊的运算符,它是一个接一个的 2 个标准运算符:

  1. 前缀减量 ( --)
  2. 逻辑非 ( !)

这会导致pending递减,然后测试它是否为零。

于 2015-12-16T22:43:11.433 回答
109

许多答案描述这个命令的作用,但没有描述为什么在这里这样做。

我来自 C 世界,我读到!--pending“倒计时pending并检查它是否为零”而没有真正考虑过。这是一个我认为类似语言的程序员应该知道的习语。

该函数用于readdir获取文件和子目录的列表,我将它们统称为“条目”。

该变量pending跟踪其中有多少需要处理。它以列表的长度开始,并随着每个条目的处理而向下计数为零。

这些条目可能会被乱序处理,这就是为什么需要倒计时而不是仅仅使用简单的循环。当所有条目都被处理后,回调done被调用来通知原始调用者这个事实。

在第一次调用前done加上return,不是因为我们想要返回一个值,而只是为了让函数在该点停止执行。放弃return并将替代方案放入else.

于 2015-12-17T09:34:01.627 回答
36

这是一个简写。

!不是”。

--递减一个值。

因此!--检查通过否定递减值的结果获得的值是否为假。

试试这个:

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

第一个为假,因为 x 的值为 1,第二个为真,因为 x 的值为 0。

旁注: !x--将首先检查 x 是否为假,然后将其递减。

于 2015-12-16T22:44:24.603 回答
31

!是 JavaScript NOT运算符

--是一个预减运算符。所以,

x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
          // which makes the condition to be true
于 2015-12-16T22:43:55.493 回答
24
if(!--pending)

方法

if(0 == --pending)

方法

pending = pending - 1;
if(0 == pending)
于 2015-12-17T16:51:41.933 回答
13

它是非运算符,后跟就地预减量器。

所以如果pending是一个值为 1 的整数:

val = 1;
--val; // val is 0 here
!val // evaluates to true
于 2015-12-16T22:45:13.613 回答
12

解释

这是 2 个运算符,a!和 a--

!--x 

因此,将--x 减 1,!如果 x 现在为 0(或 NaN ...)则返回 true,否则返回 false。你可能会读到这个成语,比如“我们递减 x,如果这使它为零......”

如果你想让它更具可读性,你可以:

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>

小提琴(试用代码)

于 2015-12-23T00:30:14.937 回答
11

它只是减pending一并获得其逻辑补(否定)。任何不同于 0 的数的逻辑补码是false,对于 0 它是true

于 2015-12-16T22:46:23.230 回答
8

这里真正的问题是两个运算符!--.

我不知道为什么人们会想到你永远不能在!操作符后面使用空格。我认为它来自机械空白规则的严格应用,而不是常识。我见过的几乎所有编码标准都在所有一元运算符之后都禁止使用空格,但为什么呢?

如果曾经有过您明显需要该空间的情况,那就是其中一个。

考虑这段代码:

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

不仅是!--捣碎在一起,你也得到了(猛烈抨击他们。难怪很难说出什么与什么有关。

更多的空格使代码更清晰:

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

当然,如果您习惯了诸如“括号内没有空格”和“一元运算符后没有空格”之类的机械规则,这可能看起来有点陌生。

但是看看额外的空格是如何分组和分隔if语句和表达式的各个部分的:你已经得到了--pending,所以--很明显它是它自己的运算符,并且与pending. (它递减pending并返回递减的结果。)然后你得到了!与它分离的,所以它显然是一个不同的运算符,否定结果。最后,你已经得到if()包围了整个表达式以使其成为一个if语句。

是的,我删除了 and 之间if空格(因为. 这不是某种语法的一部分,因为它似乎在原始语法中,即语句本身语法的 if 部分。( if((!--(if

这里的空格用于传达含义,而不是遵循一些机械编码标准。

于 2015-12-19T10:03:46.780 回答