我写了一个非常简单的基准:
console.time('var');
for (var i = 0; i < 100000000; i++) {}
console.timeEnd('var')
console.time('let');
for (let i = 0; i < 100000000; i++) {}
console.timeEnd('let')
如果您运行的是Chrome,则可以在此处进行尝试(因为NodeJS和Chrome使用相同的JavaScript引擎,尽管通常版本略有不同):
// Since Node runs code in a function wrapper with a different
// `this` than global code, do that:
(function() {
console.time('var');
for (var i = 0; i < 100000000; i++) {}
console.timeEnd('var')
console.time('let');
for (let i = 0; i < 100000000; i++) {}
console.timeEnd('let')
}).call({});
结果令我惊讶:
var: 89.162ms
let: 320.473ms
我已经在Node 4.0.0 && 5.0.0 && 6.0.0中对其进行了测试,每个节点版本之间的var
和比例let
相同。
有人可以向我解释这种看似奇怪的行为的原因是什么?
基于var
vs.
的机制差异let
,这与以下事实有关:var
存在于匿名函数的整个块范围中,而let
仅存在于循环中,并且每次迭代都必须重新声明。1这是说明这一点的示例:
(function() {
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(`i: ${i} seconds`);
}, i * 1000);
}
// 5, 5, 5, 5, 5
for (let j = 0; j < 5; j++) {
setTimeout(function() {
console.log(`j: ${j} seconds`);
}, 5000 + j * 1000);
}
// 0, 1, 2, 3, 4
}());
请注意,在i
循环的所有迭代中共享,而let
不是。根据您的基准,似乎node.js尚未针对其优化作用域规则,let
因为它比以前更新且复杂得多var
。
这是对let
in for
循环的一些外行解释,适用于那些不关心细致的规范,但好奇如何let
在每次迭代中重新声明而又保持连续性的人。
但是
let
不可能每次迭代都重新声明,因为如果在循环内更改它,它将传播到下一个迭代!
首先,这里有一个几乎可以证明这一潜在反论点的例子:
(function() {
for (let j = 0; j < 5; j++) {
j++; // see how it skips 0, 2, and 4!?!?
setTimeout(function() {
console.log(`j: ${j} seconds`);
}, j * 1000);
}
}());
您部分正确,因为更改尊重的连续性j
。但是,对于每次迭代,仍然需要重新声明它,如Babel所示:
"use strict";
(function () {
var _loop = function _loop(_j) {
_j++; // here's the change inside the new scope
setTimeout(function () {
console.log("j: " + _j + " seconds");
}, _j * 1000);
j = _j; // here's the change being propagated back to maintain continuity
};
for (var j = 0; j < 5; j++) {
_loop(j);
}
})();
就像有人说的那样。复杂的规则。毫无疑问,基准测试表现出如此巨大的性能差异(目前)。希望将来会进一步优化。
1:在Babel的REPL上查看此转译版本,以观看演示。let
在这样的for
循环中声明变量时会发生什么情况,即创建了一个新的声明性环境来保存该变量(在此处进行详细说明),然后 为每次循环迭代 创建 另一个 声明性环境来保存该变量的每次迭代副本;
每次迭代的副本都是从前一个的值初始化的(此处有详细信息),但是它们是独立的变量,如闭包所输出的值所示。
问题内容: 我读到 增强的for循环 比普通的 for循环 更有效: http://developer.android.com/guide/practices/performance.html#foreach 当我搜索它们的效率之间的差异时,我发现的是:如果是普通的for循环,我们需要一个额外的步骤来找出数组的长度或大小等, 但这是唯一的原因,增强的for循环优于普通的for循环吗?在那种情况下,
} 链接:https://www.hackerrank.com/challenges/java-string-compare/problem
问题内容: 我想做的是请用户输入一些字符串以读入数组,然后要求用户输入该数量的字符串并将其读入数组。当我运行此代码时,它从不要求我在第一个for循环的第一个循环中输入内容,只打印出“字符串#0:字符串#1:”,然后我就可以输入文本了。为什么会这样,我做错了什么? 问题答案: 缓冲。 输入输入数量时,不会在输入缓冲区中占用换行符的位置。在for循环的迭代0中,缓冲区中已经有一行输入,并且可以立即完成
为什么比: memcmp是CPU指令还是什么?它一定很深,因为我在循环中使用获得了巨大的加速。
据我所知,流比传统的旧编程更快。 然而,当我运行下面的代码时,结果是我没有预料到的。 输出为:22857304
问题内容: 用JavaScript 编写循环的正确方法是什么?浏览器不会对我在此处显示的两种方法提出任何投诉。首先,有一种方法可以明确声明迭代变量: 另外,这种方法更自然,但对我而言似乎不正确: 问题答案: 使用,它会减小变量的范围,否则变量将查找最接近的闭包以查找语句。如果找不到,则表示它是全局的(如果处于严格模式下,则全局变量将引发错误)。这可能会导致如下问题。 如果您在for循环中编写警报,