JavaScript 中的“!--”有什么作用?
What does "!--" do in JavaScript?
我有这段代码(摘自this question):
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
。在这种情况下,该命令的作用是什么?
编辑:感谢所有进一步的评论,但问题已得到多次回答。无论如何谢谢!
这不是一个特殊的运算符,它是一个接一个的 2 个标准运算符:
- 一个前缀递减(
--
)
- 逻辑非 (
!
)
这会导致 pending
递减,然后测试它是否为零。
!
是 JavaScript NOT 运算符
--
是预递减运算符。所以,
x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
// which makes the condition to be true
这是一个 shorthand。
!
是 "not".
--
递减一个值。
所以!--
检查对一个值的递减结果求反得到的值是否为假
试试这个:
var x = 2;
console.log(!--x);
console.log(!--x);
第一个为假,因为 x 的值为 1,第二个为真,因为 x 的值为 0。
旁注:
!x--
会先检查 x 是否为假,然后递减它。
!
反转一个值,并给你相反的布尔值:
!true == false
!false == true
!1 == false
!0 == true
--[value]
从数字中减去一 (1),然后 returns 要处理的数字:
var a = 1, b = 2;
--a == 0
--b == 1
因此,!--pending
从 pending 中减一,然后 returns 其 truthy/falsy 值的相反值(无论是否为 0
)。
pending = 2; !--pending == false
pending = 1; !--pending == true
pending = 0; !--pending == false
是的,请按照专业提示进行操作。这可能是其他编程语言中的常见习语,但对于大多数声明式 JavaScript 编程来说,这看起来很陌生。
它是非运算符后跟就地预递减器。
所以如果 pending
是一个值为 1 的整数:
val = 1;
--val; // val is 0 here
!val // evaluates to true
它只是将pending
减一并得到它的逻辑补码(否定)。任何不同于 0 的数字的逻辑补码是 false
,对于 0 它是 true
.
许多答案描述了什么这个命令的作用,但没有为什么它是这样做的。
我来自C世界,我把!--pending
读成"count down pending
and check if it is zero",没有认真思考过。是我觉得类似语言的程序员应该知道的成语。
该函数使用readdir
获取文件和子目录列表,我统称为"entries"。
变量 pending
跟踪其中有多少待处理。它从列表的长度开始,并在处理每个条目时向下计数到零。
这些条目可能会被乱序处理,这就是为什么需要倒计时而不是仅仅使用简单循环的原因。当 所有 条目都已处理时,回调 done
被调用以通知原始调用者这一事实。
在对 done
的第一次调用中以 return
为前缀,并不是因为我们想要 return 一个值,而只是为了使函数在该点停止执行。删除 return
并将替代项放在 else
.
中会是更简洁的代码
if(!--pending)
表示
if(0 == --pending)
表示
pending = pending - 1;
if(0 == pending)
这里真正的问题是两个运算符 !
和 --
之间缺少 space。
我不知道为什么人们会认为您永远不能在 !
运算符之后使用 space。我认为它来自机械白space 规则而不是常识的严格应用。我见过的几乎所有编码标准在所有一元运算符之后都禁止 spaces,但为什么呢?
如果曾经有过你明确需要 space 的情况,这就是一个。
考虑这段代码:
if (!--pending)
done(null, results);
不仅 !
和 --
混在一起,(
也受到了冲击。难怪很难说出什么与什么有关。
白一点space让代码更清晰:
if( ! --pending )
done( null, results );
当然,如果您习惯了像 "no space inside parens" 和 "no space after a unary operator" 这样的机械规则,这可能看起来有点陌生。
但是看看额外的白色space如何分组和分隔if
语句和表达式的各个部分:你有--pending
,所以--
显然是它自己的运算符,并且与 pending
紧密相关。 (它递减 pending
和 returns 递减的结果。)然后你将 !
与它分开,所以它显然是一个不同的运算符,否定了结果。最后,你用 if(
和 )
包围了整个表达式,使其成为一个 if
语句。
是的,我删除了 if
和 (
之间的 space,因为 (
属于 if
。这个 (
不是某种 (!--
语法的一部分,因为它似乎是原始语法的一部分, (
if 是 if
语句本身的语法的一部分。
此处的白色space用于传达意思,而不是遵循一些机械编码标准。
说明
这是 2 个运算符,一个 !
和一个 --
!--x
因此,--
将 x 减 1,然后 !
returns 如果 x 现在为 0(或 NaN...)则为真,否则为假.您可能会读到类似 "we decrement x and if that makes it zero..."
的成语
如果你想让它更具可读性,你可以:
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>
我有这段代码(摘自this question):
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
。在这种情况下,该命令的作用是什么?
编辑:感谢所有进一步的评论,但问题已得到多次回答。无论如何谢谢!
这不是一个特殊的运算符,它是一个接一个的 2 个标准运算符:
- 一个前缀递减(
--
) - 逻辑非 (
!
)
这会导致 pending
递减,然后测试它是否为零。
!
是 JavaScript NOT 运算符
--
是预递减运算符。所以,
x = 1;
if (!x) // false
if (!--x) // becomes 0 and then uses the NOT operator,
// which makes the condition to be true
这是一个 shorthand。
!
是 "not".
--
递减一个值。
所以!--
检查对一个值的递减结果求反得到的值是否为假
试试这个:
var x = 2;
console.log(!--x);
console.log(!--x);
第一个为假,因为 x 的值为 1,第二个为真,因为 x 的值为 0。
旁注:
!x--
会先检查 x 是否为假,然后递减它。
!
反转一个值,并给你相反的布尔值:
!true == false
!false == true
!1 == false
!0 == true
--[value]
从数字中减去一 (1),然后 returns 要处理的数字:
var a = 1, b = 2;
--a == 0
--b == 1
因此,!--pending
从 pending 中减一,然后 returns 其 truthy/falsy 值的相反值(无论是否为 0
)。
pending = 2; !--pending == false
pending = 1; !--pending == true
pending = 0; !--pending == false
是的,请按照专业提示进行操作。这可能是其他编程语言中的常见习语,但对于大多数声明式 JavaScript 编程来说,这看起来很陌生。
它是非运算符后跟就地预递减器。
所以如果 pending
是一个值为 1 的整数:
val = 1;
--val; // val is 0 here
!val // evaluates to true
它只是将pending
减一并得到它的逻辑补码(否定)。任何不同于 0 的数字的逻辑补码是 false
,对于 0 它是 true
.
许多答案描述了什么这个命令的作用,但没有为什么它是这样做的。
我来自C世界,我把!--pending
读成"count down pending
and check if it is zero",没有认真思考过。是我觉得类似语言的程序员应该知道的成语。
该函数使用readdir
获取文件和子目录列表,我统称为"entries"。
变量 pending
跟踪其中有多少待处理。它从列表的长度开始,并在处理每个条目时向下计数到零。
这些条目可能会被乱序处理,这就是为什么需要倒计时而不是仅仅使用简单循环的原因。当 所有 条目都已处理时,回调 done
被调用以通知原始调用者这一事实。
在对 done
的第一次调用中以 return
为前缀,并不是因为我们想要 return 一个值,而只是为了使函数在该点停止执行。删除 return
并将替代项放在 else
.
if(!--pending)
表示
if(0 == --pending)
表示
pending = pending - 1;
if(0 == pending)
这里真正的问题是两个运算符 !
和 --
之间缺少 space。
我不知道为什么人们会认为您永远不能在 !
运算符之后使用 space。我认为它来自机械白space 规则而不是常识的严格应用。我见过的几乎所有编码标准在所有一元运算符之后都禁止 spaces,但为什么呢?
如果曾经有过你明确需要 space 的情况,这就是一个。
考虑这段代码:
if (!--pending)
done(null, results);
不仅 !
和 --
混在一起,(
也受到了冲击。难怪很难说出什么与什么有关。
白一点space让代码更清晰:
if( ! --pending )
done( null, results );
当然,如果您习惯了像 "no space inside parens" 和 "no space after a unary operator" 这样的机械规则,这可能看起来有点陌生。
但是看看额外的白色space如何分组和分隔if
语句和表达式的各个部分:你有--pending
,所以--
显然是它自己的运算符,并且与 pending
紧密相关。 (它递减 pending
和 returns 递减的结果。)然后你将 !
与它分开,所以它显然是一个不同的运算符,否定了结果。最后,你用 if(
和 )
包围了整个表达式,使其成为一个 if
语句。
是的,我删除了 if
和 (
之间的 space,因为 (
属于 if
。这个 (
不是某种 (!--
语法的一部分,因为它似乎是原始语法的一部分, (
if 是 if
语句本身的语法的一部分。
此处的白色space用于传达意思,而不是遵循一些机械编码标准。
说明
这是 2 个运算符,一个 !
和一个 --
!--x
因此,--
将 x 减 1,然后 !
returns 如果 x 现在为 0(或 NaN...)则为真,否则为假.您可能会读到类似 "we decrement x and if that makes it zero..."
如果你想让它更具可读性,你可以:
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>