When I test following code in chrome and nodejs, I get following:
Chrome:
for loop with VAR: 24.058ms
for loop with LET: 8.402ms
NodeJS:
for loop with VAR: 4.329ms
for loop with LET: 8.727ms
As per my understanding, because of block scoping LET is faster in chrome. But can someone help me understand why is it opposite in NodeJS?
Or am i missing something?
"use strict";
console.time("for loop with VAR");
for (var i = 0; i < 1000000; i += 1) {
// Do nothing
}
console.timeEnd("for loop with VAR");
console.time("for loop with LET");
for (let i = 0; i < 1000000; i += 1) {
// Do nothing
}
console.timeEnd("for loop with LET");`
PS: Not sure if this is not the ideal way to test performance.
V8 version shipped with node.js 5.10 don't support the temporal dead zone for let bindings.
Chrome instead is using V8 5.0 that support it...but as the vm is not yet optimized to handle TDZ, is normal that for now it's slower (I remember reading people who assert that replacing var with let made the code about 27% slower).
When you do
for (let i = 0; i < 1000000; i += 1) { }
the i value in each loop cycle is a separate reference, which is useful when using the i value in an asynchronous callback. This is slower, but can be faster than alternatives in this usage case.
When instead you use
let j;
for (j = 0; j < 1000000; ++j) { }
you will only have one value reference, and it will be just as fast as with var.
Try the following code
console.time("let i");
for (let i = 0; i < 10000000; ++i) { }
console.timeEnd("let i");
console.time("let j");
let j;
for (j = 0; j < 10000000; ++j) { }
console.timeEnd("let j");
console.time("var k");
for (var k = 0; k < 10000000; ++k) { }
console.timeEnd("var k");
this will give results like
let i: 91ms
let j: 25ms
var k: 27ms
where clearly let is equally fast to var when used correctly.
Also to see the difference in asynchronous behaviour, try
for (let i = 0; i < 3; ++i) {
setImmediate(() => { console.log(i) });
}
let j;
for (j = 0; j < 3; ++j) {
setImmediate(() => { console.log(j) });
}
for (var k = 0; k < 3; ++k) {
setImmediate(() => { console.log(k) });
}
which will output
0
1
2
3
3
3
3
3
3
as in each cycle of the loop for let i the i value is a unique reference, which is what causes the slight overhead, whereas for the other two loops it's the same reference.
i can't tell you more but as mentiont in this video (very good), you need smarter code to test this.
https://www.youtube.com/watch?v=65-RbBwZQdU
the compiler will to magic stuff with your code and might even ereas the loop if you don't use i and the loop is empty
Related
I am trying to write a function which should calculate all prime numbers up to an input parameter and return it. I am doing this for practice.
I wrote this function in a few ways but I was trying to find new ways to do this for more practice and better performance. The last thing I tried was the code below:
function primes(num){
let s = []; // sieve
for(let i = 2; i <= num; i++){
s.push(i);
}
for(let i = 0; i < s.length; i++) {
for(let j = s[i]*s[i]; j <= num;) {
//console.log(j);
if(s.indexOf(j)!= -1){
s.splice(s.indexOf(j), 1, 0);
}
j+=s[i];
}
}
s = s.filter(a => a != 0);
return s;
}
console.log(primes(10));
The problem is that when I run this in a browser it keeps calculating and won't stop and I don't know why.
Note: when I comment out the splice and uncomment console.log(j); everything works as expected and logs are the things they should be but with splice, the browser keep calculating and won't stop.
I am using the latest version of Chrome but I don't think that can have anything to do with the problem.
Your problem lies in this line:
s.splice(s.indexOf(j), 1, 0);
Splice function third argument contains elements to be added in place of the removed elements. Which means that instead of removing elements, you are swapping their values with 0's, which then freezes your j-loop.
To fix it, simply omit third parameter.
function primes(num){
let s = []; // sieve
for(let i = 2; i <= num; i++){
s.push(i);
}
for(let i = 0; i < s.length; i++) {
for(let j = s[i]*s[i]; j <= num;) {
//console.log(j);
if(s.indexOf(j)!= -1){
s.splice(s.indexOf(j), 1);
}
j+=s[i];
}
}
return s;
}
console.log(primes(10));
Your problem is in this loop:
for(let j = s[i]*s[i]; j <= num;)
This for loop is looping forever because j is always less than or equal to num in whatever case you're testing. It is very difficult to determine exactly when this code will start looping infinitely because you are modifying the list as you loop.
In effect though, the splice command will be called setting some portion of the indexes in s to 0 which means that j+=s[i] will no longer get you out of the loop.
I see examples like this online:
const roles = [];
for (i of roles) {
roleObj[roles[i].key] = true;
}
do we need not declare the variable i, like so?
for (let i of roles) {
roleObj[roles[i].key] = true;
}
tons of articles are promoting the first example, which seems pretty dumb to me:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
You don't absolutely need to, but it's highly recommended to do so and in fact to use let. Note that using let i in this case will actually function differently than if you just did for (i or for (var i.
As an example:
for (let i = 0; i < 10; i++) {
process.nextTick(() => console.log(i));
}
// print 0..9
for (var i = 0; i < 10; i++) {
process.nextTick(() => console.log(i));
}
// prints 10 ten times.
Also note that with let you would not be able to use i after the loop, but you could with var, and if you do not use var the variable will be in the global scope so it would work differently if it were inside of a function:
function gl() {
for (i = 0; i < 10; i++) {}
for (var j = 0; i < 10; i++) {}
for (let x = 0; i < 10; i++) {}
console.log(i, j) // prints 10, 10
console.log(x) // runtime error
}
gl();
console.log(i) // prints 10
console.log(j) // runtime error
Also, as mentioned in the comments, accessing variables without declarations is not allowed in strict mode.
What would be the difference between
var nums = [];
for (var i = 0; i < 10; ++i) {
nums[i] = i+1;
}
and
var nums = [];
for (var i = 0; i < 10; i++) {
nums[i] = i+1;
}
In the for loop, i = 0, but in the first iteration, would nums[i] = nums [0] or nums [1] since we are using ++i? How would the first iteration be different if i++ were used instead?
Update: For this particular for loop it doesn't matter. However, I'm interested to see a for loop where ++i vs i++ matters.
They would be exactly the same; ++i and i++ have the same effect on i, but the value of each expression is different; in this context, since the value is ignored, the code behaves the same.
As an example where switching between the two would matter, here is some truly awful code:
for ( var i=0; i++ < 10; )
++i increments before the "return", i++ increments after
var i = 0;
i++; //=> 0
i; //=> 1
var j = 0;
++j; //=> 1
j; //=> 1
For the purposes of your for loop, it doesn't make a difference.
In for loops, there is no difference. The difference between ++i and i++ is the value returned by the expression, but the expression is evaluated after each pass of the loop and you ignore the value.
There is no difference between the two. The incremented value will be ignoreed as it will happen at the end of the loop.
EDIT:
It makes no difference in the for loop if you write
for (var i = 0; i < 10; ++i) {
or
for (var i = 0; i < 10; i++) {
You will get the same results in both the cases. The reason why most of the people use i++ or better to say why i++ is more popular over ++i in a for loop is probably because people come from a habit of using i++ which was majorly used in C. Also to note that in C++ you can write your own version of ++ operator.
They are the same. The increment occurs at the end of the body of the loop.
i.e. you can view the loop as
var i = 0;
while (i < 10) {
... Body of loop
i++ or ++i;
}
i have function:
function getFieldNames(arrayOfRecords) {
var theStuff;
for (var i = 0; i = arrayOfRecords.length - 1; i++){
theStuff = arrayOfRecords[i];
theList = theStuff.split('" ');
for (var j = 0; j = theList.length - 1; j++) {
var v = theList[j].split('="');
fName1[i][j] = v[0];
}
}
return fName1;
}
the argument arrayOfRecords is an array, and i dont know how to setup to the 'theStuff' variable an array element? When I do like it is above, i get something stupid.
can anyone help me? :)
There may be other problems but the one that leaps out at me is your for loop header:
for (var i = 0; i = arrayOfRecords.length - 1; i++)
The second part should be a condition, which when evaluated to false will stop the loop from running. What you probably wanted was:
for (var i = 0; i < arrayOfRecords.length; i++)
So when i is not less than arrayOfRecords.length, the loop will stop. Alternatively (to keep the - 1, but I tend to use the above version):
for (var i = 0; i <= arrayOfRecords.length - 1; i++)
The same goes for the nested loop.
Why do nested for loops work in the way that they do in the following example:
var times = [
["04/11/10", "86kg"],
["05/12/11", "90kg"],
["06/12/11", "89kg"]
];
for (var i = 0; i < times.length; i++) {
var newTimes = [];
for(var x = 0; x < times[i].length; x++) {
newTimes.push(times[i][x]);
console.log(newTimes);
}
}
In this example I would have thought console.log would give me the following output:
["04/11/10"]
["86kg"]
["05/12/11"]
["90kg"]
["06/12/11"]
["89kg"]
However, I actually get this:
["04/11/10"]
["04/11/10", "86kg"]
["05/12/11"]
["05/12/11", "90kg"]
["06/12/11"]
["06/12/11", "89kg"]
Is anyone able to help me understand this?
EDIT:
Thanks for all your responses!
You are redefining newTimes on every single loop and you are outputting to the console on each column push.
var times = [
["04/11/10", "86kg"],
["05/12/11", "90kg"],
["06/12/11", "89kg"]
];
var newTimes = [];
for (var i = 0; i < times.length; i++) {
for(var x = 0; x < times[i].length; x++) {
newTimes.push(times[i][x]);
}
}
console.log(newTimes);
Returns: ["04/11/10", "86kg", "05/12/11", "90kg", "06/12/11", "89kg"]
http://jsfiddle.net/niklasvh/SuEdt/
// remember that the increment of the counter variable
// is always executed after each run of a loop
for (var i = 0; i < n; i++) {
// some statement(s) to do something..
// initializes child-loop counter in the first run of the parent-loop
// resets child-loop counter in all following runs of the parent-loop
// while i is greater than 0 and lower than n
for (var j = 0; j < p; j++) {
// some statement(s) to do something..
// initializes grandchild-loop counter in the first run of the child-loop
// resets grandchild-loop counter in all following runs of the child-loop
// while j is greater than 0 and lower than p
for (var k = 0; k < q; k++) {
// some statement(s) to do something..
// or add more internal loop-nestings if you like..
}
}
}
// if the counter variables of the descendent-loops were set before the loop-nesting,
// the inner loops would only run once, because the counter would keep the value
// of the abortion condition after the loop is finished
Do this:
var newTimes = [];
for (var i = 0; i < times.length; i++) {
for(var x = 0; x < times[i].length; x++) {
newTimes.push(times[i][x]);
console.log(newTimes);
}
}
You are re-initializing newTimes each time through the loop.
You output would be appropriate if the log statement would read
console.log(times[i][x]);
Instead you output your complete new list newTimes which is initialized outside the inner loop and grows with each inner loop iteration.
The problem is in the second round of the inner loop, where it pushes the second element into newTimes. Anyway I don't understand the reason of inner loop. You can write much simpler:
var times = [
["04/11/10", "86kg"],
["05/12/11", "90kg"],
["06/12/11", "89kg"]
];
for (var i = 0; i < times.length; i++) {
console.log(time[i][0]);
console.log(time[i][1]);
}