Getting html elements in a for loop - javascript

This for loop does not run. This simple code is supposed to get all of the H5 elements on the page then get the "innerHTML" but the code never runs the for loop.
function myFunction() {
var x = document.getElementsByTagName("h5").length;
alert(x);
var y;
var z;
for (i = 0; i < x.length; i++) {
y = document.getElementsByTagName("h5")[i];
z = y.innerHTML;
alert(z + " this");
}
}

You're looking for a .length property on x which is itself a length number. I think you mean:
var x = document.getElementsByTagName("h5");
Or of course
for (i = 0; i < x; i++) {
Depending on what you're doing with x afterwards

var x = document.getElementsByTagName("h5").length;
// ...
for (i = 0; i < x.length; i++) {
You're calling .length twice.

The other answers are correct, but here's a little refactoring with some explanations.
function myFunction() {
// Taking out the '.length' means you have a reference to all the h5s
var x = document.getElementsByTagName("h5");
alert(x);
var y;
var z;
//Now since you're not including the .length above, this loop is correct
for (i = 0; i < x.length; i++) {
//You since x is a reference to all the h5s now you don't
//have to search for them again.
y = x[i];
z = y.innerHTML;
alert(z + " this");
}
}
The important part there is just to use one getElementsByTagName call since that's a relatively expensive function. You definitely don't want to call it in a loop if you can avoid it. Generally to write good javascript you want to reuse references to DOM Elements as much as possible since the DOM is much slower than Javascript.

Related

Why won't my function work when I use splice?

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.

Why do I only receive a single alert from the following javascript?

This is a javascript function inside of a HTML tag, however - when I move the alert(currentalbum) below the for loop, the second alert does not run - only the first, why?
function populatetracks(albumvalue) {
var currentalbum = albumvalue;
alert(currentalbum); // #1
document.getElementById("TracksList").options.length = 0;
for(i = 0; albums[albumvalue].tracks.length - 1; i++) {
var s = document.getElementById('TracksList');
var opt = document.createElement('option');
opt.appendChild( document.createTextNode(albums[albumvalue].tracks[i].title));
opt.value = i;
s.appendChild(opt);
}
alert(currentalbum); // #2
}
'#1' does produce an alert, but '#2' doesn't.
As noted, not sure how your for loop is supposed to stop.
This has no evaluation in it, just an incrementor
for(i=0; albums[albumvalue].tracks.length -1; i++){
Maybe try this (might need to change '=' to '<=' )
for(i=0; i < albums[albumvalue].tracks.length -1; i++){

JavaScript uninitialised variable behaviour

i am learning JavaScript. I encountered this behaviour using initialised and uninitialised variable.
For example,
//Not initialised
var sum;
for(var i = 0; i < 10; i++)
{
sum = sum + i;
}
alert(sum);
output:90
//Initialised
var sum = 0;
for(var i = 0; i < 10; i++)
{
sum = sum + i;
}
alert(sum);
output:45
Could someone explain me what is happening here? I think not initialised variable sum adds 45 two times it seems.
Edit:
Please try running the code separately.
First one would return NaN (not a number). I don't think it would alert 90. I didn't, I tried your script.
while in the second one you explicitly inform the script that you are using numbers
var sum = 0;
for(var i = 0; i < 10; i++)
{
sum = sum + i;
}

What are the differences between var i = somevalue; and var i; i = somevalue;

To begin with, I apologize if this question has been asked previously. I have searched for something similar to what I'm asking here and have found nothing but dead ends.
I am reviewing some older code for a project and I am using Brackets as my IDE with the JSLint extension. While going through my code it recommended that I change a line similar to
for(var i = 0; i < somevalue; i++)
to
var i;
for(i = 0; i < somevalue; i++)
This prompted me to ask; is there is any significant difference between the two declarations from a performance aspect, coding standard aspect, or etc.?
Thank you for any answers or leads!
JSLint is actually asking you to move the variable declaration to the top of the function scope:
function myfunction() {
var i,
j,
k;
// other code
for (i = 0; i < 100; i=i+1) { //another JSLint Recommendation: Don't use ++
for (j = 0; j < 100; j=j+1) {
for (k = 0; k < 100; k=k+1) {
console.log(i);
console.log(j);
console.log(k);
}
}
}
}
The reason is that variables have function level scope in JavaScript. If I had declared 'j' inside of the for loop for i, it would have been 'hoisted' to the top of the function and would have actually existed throughout that whole function, not just in the for loop.
JSLint makes this recommendation because that's what is going on behind the scenes anyway, and you could be in for a rude surprise if you don't expect that to be the case.
Consider following 2 functions
function test1(){
//code block 1
for(var i = 0; i < somevalue; i++)
//code block 2
}
function test2(){
//code block 1
var i;
for(i = 0; i < somevalue; i++)
//code block 2
}
In both cases the definitions are hoisted and the compiler first defines the variables. The compiler rearranges the code like this,
function test(){
var i; //and other definitions
//code block 1(without definitions)
for(i = 0; i < somevalue; i++)
//code block 2(without definitions)
}
Therefore there is no difference..
var i binds the variable i to the local context. If you don't do var i, the variable is defined globally.
you should always use var in only one place, at least this is the best practice. Also you should use it per variable only once
so
for(var i = 0;i<10;i++)
is fine but
for(var i = 0;i<10;i++)
for(var i = 0;i<10;i++)
is not good better would be
for(var i = 0;i<10;i++)
for(i = 0;i<10;i++)
but if you do
var i;
for(i = 0;i<10;i++)
or not is totaly up to you

first loop stops when the second starts

I want to use a for loop in another for loop to get the content of an xml file.
The problem is that when the second loop starts the first one stops.
javascript code:
var x = xmlDoc.getElementsByTagName('usr');
for (i=0; i <= x.length; i++) {
var y = x[i].childNodes;
for(n=0; n <= y.length; n++) {
var z = y[n].childNodes[0];
document.write(z.nodeValue);
}
}
xml code:
<usr><age>30</age><location>uk</location></usr>
<usr><age>25</age><location>usa</location></usr>
And the output is:
30uk
It should be 30uk25usa
In both of your loops, you will iterate one too many times.
i=0; i<=x.length should be i = 0; i < x.length and same for the inner loop.
Iterating one too many times generates an error, which breaks the execution
Try storing the total result that you want outside of the first loop, and then use document.write() after the outer loop completes:
var x = xmlDoc.getElementsByTagName('usr');
var zTotal = '';
for (i=0; i < x.length; i++) {
var y = x[i].childNodes;
for(n=0; n < y.length; n++) {
var z = y[n].childNodes[0];
zTotal += z.nodeValue;
}
}
document.write(zTotal);

Categories