My teacher showed us this piece of code at the end of my cs class today and asked us to think about why it was not optimal.
Here is the code:
for (var x = 0; x < array.length; x++) {
console.log(array[x]);
}
I can't figure out what's wrong. I think maybe it is better to use a 'forEach' perhaps, but I'm not sure why?
Something like this?:
array.forEach(function(element) {
console.log(element);
});
You could probably just go with:
for(const el of array) { /*...*/ }
Why is that better? Well, you just need to look at it once, to get that it executes the block for every el of array. Its much faster to read than:
for(let i = 0; i < array.length; i++) {
const el = array[i];
/*...*/
}
And as programming languages are mainly there to be easily understandable by humans, you should always try to make the code as readable as possible. And it is also easier to spot bugs in the code if it is more readable, therefore increasing security, maintainability and development time.
By keeping the for loop, you could omit the different return value of postfix vs prefix syntax for the increment operator ++.
x++ // take value, then increment, slower
++x // increment, take value, faster
You should get the length into a variable rather than using it as array.length in the loop. ie.
var length = array.length.
for(let i = 0; i < length; i++)
Related
let example = {
a:20,
b:40,
c:60
}
for(let j=0,i in example){
console.log(example[i]*j);
j++;
}
Why normal for loop can have multiple variable declarations, but for-in loop cannot? Or am I doing this somehow wrong?
You're writing a code that's not syntactically correct.
in JavaScript you cannot use for-in expression with any other assignment expression.
You can simply pull out the j=0 assignment out of the for loop and that should fix the error
let example = {
a:20,
b:40,
c:60
}
let j=0
for(i in example){
console.log(example[i]*j);
j++;
}
[Edit] I have the found the following content in the official MDN site for the same scenario
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
As per the site - it's a publicly known issue that ChromeV8 and other browsers are trying to look into
For more info check the following references
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_for-in_initializer
https://bugzilla.mozilla.org/show_bug.cgi?id=748550
https://bugzilla.mozilla.org/show_bug.cgi?id=1164741
I can understand the frustration, you're using the same keyword so why doesn't it behave similar? But I think you should think about it this way:
for is a way to define a loop, for as long as some condition is true, with different way for how to define that condition.
In a regular for loop, you loop as long as the middle part (the condition) is true:
for(let i = 0; i < 10; i++)
This is similar to how a while loop might work, but it's a syntactic short cut:
let i = 0;
while (i < 10) {
i++;
}
So the for..in is a for loop that has another sort of condition, for every property in this object, so as long as you have more properties it will keep looping.
You could write that like this as well:
const keys = Object.keys(example);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = example[key];
}
You also have for...of, which loops over items in a array, but that is syntactic sugar for:
for(let i = 0; i < array.length; i++) { const item = array[i]; }
Also consider how a do...while loop is like a while loop but with some slightly different rules and behavior. Rather than getting frustrated with the syntax try to understand how it's saving you time by making your code a little less wordy, but in order to do that it needs to be a little different for each case. The alternative would be to have very many language keywords.
I tried changing your code to not declare any variables inside the parentheses of the for loop. I have never seen this done; maybe it's possible, but it would be simpler to declare a variable above the for loop, like this (assuming that's what you were hoping to do):
let example = {
a:20,
b:40,
c:60
}
let j=0
for(let i in example){
console.log(example[i]*j);
j++;
}
Edit: As mentioned in the comments: "You should probably add a let before the i declaration, otherwise it's going to be globally defined." I've just changed that in the snippet!
I have value X that's supposed to be the "length" of what my loop should be (for example):
length = 10
I need to run a for loop to run length times. there's no object/array/anything I run on, nothing beyond the reference value length. is there a better way or cleaner way to write a for loop or to create a loop that runs length times in ES6 than this?
for(let i = 0; i < length ; i++)
An elegant way would be a generator for the indices:
function* range(from, to) {
for(let i = from; i < to; i++)
yield i;
}
for(const i of range(0, length)) /*...*/
But that's overengineering. A simple for loop is fine.
I don't think there is a strictly more elegant solution to that. You could write it like this
new Array(length).forEach(() => {
// do something
})
but if that's a more elegant solution is a matter of opinion.
Let's say we have the following function with a loop that writes some memory variable within each iteration of the loop.
function myFunction() {
for (var i = 0; i < 10000; i++) {
let myStackVariable = i;
// do something with myStackVariable
}
}
But let's say we re-write this loop to declare the variable only once outside of the loop and then re-assign it during the loop.
function myFunction() {
let myStackVariable;
for (var i = 0; i < 10000; i++) {
myStackVariable = i;
// do something with myStackVariable
}
}
I'm pretty sure that in any decent C compiler will optimize only a single variable in the stack and consistently use that memory location.
Will JavaScript likely do the same? Is there any benefit performance wise to doing the latter? Is it worth writing one way rather than the other. I know, I know - premature optimization is the root of all evil - but I am more curious than anything.
I tried running tests with n = 100000000 and the results were the same, but I'm unsure if my example was just too simple since there are no recursions, etc.
I'm doing a tutorial on JavaScript. The following is from a section on performance:
Each statement in a loop, including the for statement, is executed for each iteration of the loop.
Statements or assignments that can be placed outside the loop will
make the loop run faster.
This is given as an example of bad code:
var i;
for (i = 0; i < arr.length; i++) {
And this is given as an example of good code:
var i;
var l = arr.length;
for (i = 0; i < l; i++) {
This is not something I can remember seeing as a best practice in languages that are more focused on performance than JavaScript. In fact, the bad code example seems to be preferred.
Is this best practice something particular for JavaScript, or is is true for other languages?
Bad Practice
for (i = 0; i < arr.length; i++) {
For every iteration in the loop, the condition is evaluated. If it is being arr.length then every time you are trying to access length property from arr. However, on the other hand, if you are storing it in a variable you are avoiding that operation.
Of all the ways to loop in javascript, the for-in loop is the safest in my opinion.
It can loop through the properties in an object.
let user = {first:"billy", last:"bob"};
for(let i in user){
console.log(i);
console.log(user[i]);
}
It doesn't throw an error if the variable is null
let empty = null;
for (let i in empty){
}
It works with arrays
let arr = [3,2,1];
for (let i in arr){
console.log(i);
console.log(arr[i]);
}
.map
.filter
.reduce
.forEach
throw errors with anything but arrays(null, objects etc)
So if you want one loop that works for everything, for-in is you what you want.
What is the best practice for writing a JavaScript for loop?
I started out writing it like this:
for(var i = 0; i < array.length; i++){
//do stuff
}
But then I found that calculating the length on each pass is not ideal, so it should be more like:
var len = array.length;
for(var i = 0; i < len; i++){
//do stuff
}
But then the loop is faster if you decrease rather than increase:
var lenArr = array.length - 1;
for(var len = lenArr; len > 0; len--){
//do stuff
}
This kind of loop however doesn't really work if you want to break just one loop in a cluster of nested loops, so you should therefore get into the habit of using labels:
var lenArr = array.length - 1;
var lenArr2 = array2.length - 1;
loop1: for(var len = lenArr; len > 0; len--){
loop2: for(var len2 = lenArr2; len2 > 0; len2--){
//do stuff
break loop2;
}
}
Is there something else that will need to change, or is this the best practice for writing for loops in JavaScript?
IF you have array than make use of forEach
array.forEach(ele=> {
});
that way you can keep code clean and easy to understand and dont have to do length related code.
Break is not going to work with forEach but you can write return for coming out of forEach like
array.forEach(ele=> {
ele.array.forEach(ele=> {
//do stuff
return;
});
});
Note:
for loop is faster.
forEach is slower, but better fits functional programming paradigms.
Answer is based on title of question : Best Practice that why given suggestion to make use of forEach over for.
Actually, i prefer for...of as you can still break and its much less typing and its definetly more readable:
for(const el of array)
If you need indices too:
for(const [index, el] of array.entries())
Or if you need to iterate from back to front:
for(const el of array.reverse())
Concerning saving array.length: Even though in the early days of JavaScript it made a difference to save the .length value in a variable, modern JavaScript engines will run the for loop just as fast if you write it as in the first version.
Iterating backward is also not guaranteed to run faster on modern engines. There is also the consideration that CPUs are optimised to anticipate forward memory references, although this will only be relevant when the JS engine has decided to store the array as a contiguous block of memory.
As for the use of labels: most would not consider this best practice. Where the previous optimisation (concerning .length) concerns all iterations of the loop, this issue only applies to a single exit out of both loops. Whatever solution you use, it represents constant time, and could not be a determining factor in the overall performance of the loop.
So certainly in this case, I would go with good coding habits over tiny optimisation considerations. When you want to exit just the current loop, a single break is enough.
If you want to exit quickly from nested loops, then consider placing them in a function, so you can use return:
function performNestedLoop(array, array2) {
for(let i = 0; i < array.length; i++){
for(var j = 0; j < array2.length; j++){
//dostuff
if (exitCondition) return;
}
}
}
As to best practice: this really depends on what you need to achieve. There are several array methods that provide iteration, like forEach, map, reduce, reduceRight, filter, some, every, find, findIndex, includes,... each with their purpose. If they fit the purpose, then go with them. If you don't need the index, but just the value, then use for..of. If you really need every speck of optimatisation, then the old fashioned for loop is a likely winner.
You can use Array.forEach
Advantage of using forEach are as follows
Provides functional scoping, and whenever you need to perform some async function in the loop, you will not be required to created any IIFE
It keeps your code tidy and more contextual
Sample Code
arr.forEach(function(item, index){
// do stuff
});