Looping through multiple variables in a function - javascript

I've written a function that contains an if statement and the condition contains a variable.
function interval() {
var interval = setInterval(function() {
if (x < max) {
x = parseInt(x) + 1;
$('.max').html(addCommas(x));
}
}, 1);
};
So here max is my variable. Works great, but now I have three more variables and I want to run the same function but with the different variables each time. I could copy the function 3 more times and edit the variable in each one but that strikes me as highly inefficient.
What would be the best way to achieve this Stacked?

Pass max as an argument to the function
function interval(max){
var x = 0; //always declare variables
var interval = setInterval( function(){
if (x < max){
x = parseInt(x) + 1;
$('.max').html(addCommas(x));
}
}, 1);
};
I'm not sure of the driver for putting this code in an interval. You may want to consider using a for loop:
function interval(max){
for(var x = 0; x < max; x++){
$(".max").html(addCommas(x));
}
};

Use the parameters in function and use same function.
function interval(vfield){
var interval = setInterval( function(){
if (x < vfield){
x = parseInt(x) + 1;
$('.max').html(addCommas(x));
}
}, 1);
};
Where vfield is your variable.

Related

Global variable not updating outside function

Trying to make variable created inside function possible to access globally, so far
console.log(proper_head);
constantly displays "1" while I need it to be updated every time the function is executed, here is my function:
var i = 0;
function change_head() {
if (i < head_class.length) {
head.classList.add(head_class[i].name);
i++;
var h = i;
return h;
} else if (i = 3) {
head.className = "";
i -= 3;
var h = i;
return h;
}
}
var proper_head = change_head();
it is executed by pressing a button (not sure if it's important).
The only solution I came up with is to
setTimeout()
I'm sure there is a better way.
You could use a recursive implementation like this:
var i = 0;
function change_head() {
if (i < head_class.length) {
head.classList.add(head_class[i].name);
i++;
var h = i;
return h;
} else if (i = 3) {
head.className = "";
i -= 3;
var h = i;
return h;
}
change_head();
}
The problem is that your function is only being called once, you can call the function from within itself, however the above example will never stop, and will probably hit the max call stack size in your browser and then crash, i would recommend wrapping it in some sort of if statement so that it stops at some point, e.g i > 50.
Edit:
I see what your actual problem is, neither of your if blocks are firing, after the first press, head_class.length === 1 so "if (i < head_class.length)" wont fire, it's also not equal to 3 for the else block so nothing happens, the else block also has an error, try changing it to this:
if (i < 3) {
head.classList.add(head_class[i].name);
i++;
var h = i;
return h;
} else if (i == 3) {
head.className = "";
i -= 3;
var h = i;
return h;
}
i = 3 is for assignment, i == 3 is for comparison.
Hope this helps
Lloyd

How to add values from two different functions?

In my case, I found the value of 2 different sums in two different functions. Now all I need to do is subtract these two values but I am not sure if it is possible to do so from two different functions. What would be the best way to perform this?
function networth()
{
var totNoA = document.getElementsByName("number4[]").length;
var sum = 0;
for(var i=0; i<totNoA; i++)
{
sum +=parseInt(document.getElementsByName("number4[]")[i].value);
console.log(sum);
}
}
Here I have the variable 'sum' that has a value.
function networth1()
{
var totNoL = document.getElementsByName("number5[]").length;
var sumL = 0;
for(var x=0; x<totNoL; x++)
{
sumL +=parseInt(document.getElementsByName("number5[]")[x].value);
console.log(sumL);
sum - sumL = total_sum;
document.Net_worth.total1.value = total_sum;
}
}
I would like to subtract sum - sumL but I am not doing it right. Any thoughts?
You can also return sum from networth function like this :
function networth()
{
var totNoA = document.getElementsByName("number4[]").length;
var sum = 0;
for(var i=0; i<totNoA; i++)
{
sum +=parseInt(document.getElementsByName("number4[]")[i].value);
console.log(sum);
}
return sum;
}
And then you can use it's value in your networth1 function, like below :
function networth1()
{
var totNoL = document.getElementsByName("number5[]").length;
var sumL = 0;
for(var x=0; x<totNoL; x++)
{
sumL +=parseInt(document.getElementsByName("number5[]")[x].value);
console.log(sumL);
}
var sum = networth();
total_sum = sum - sumL;
document.Net_worth.total1.value = total_sum;
}
You don't need to calculate difference inside loop as you are requiring only the final difference. Also you can follow what other has suggested here. Make sum and sumL global variables instead of making them local.
You have to define sum and sumL in the global scope. Move var sum = 0 and var sumL = 0 outside of the functions, and get their difference using sum-sumL.
These functions should return the sum values and write one more function that performs subtraction using values returned by these functions
Note :write the functions small n self explainable it improves code maintainability
In your code, you do two searches in the DOM with document.getElementsByName in each function, but this is not needed.
Simplifying your own code, it would look like this:
function netWorth(query) {
var elements = document.getElementsByName(query);
var sum = 0;
for(var i = 0; i < elements.length; i++) {
sum += parseInt(elements[i].value);
}
return sum;
}
var sum = netWorth("number4[]");
var sumL = netWorth("number5[]");
document.Net_worth.total1.value = (sum - sumL);

javascript for-loop and timeout function

I am facing an issue with a for-loop running a setTimeout.
for (var x = 0; x < 5; x++) {
var timeoutFunction = function() {
return function() {
console.log(x)
}
}
setTimeout(timeoutFunction(), 1)
}
I expect the output
0
1
3
4
Yet, for some reason they all output 5.
Variable x is defined in the local scope of the for-loop, so I thought this may not count for the callback of setTimeout. I tested with defining x outside of the for-loop.
var x = 10
for (var x = 0; x < 5; x++) {
var timeoutFunction = function() {
return function() {
console.log(x)
}
}
setTimeout(timeoutFunction(), 1)
}
I figured this output would be giving 10, yet it didn't. Then I thought it would make sense to define x afterwards.
for (var x = 0; x < 5; x++) {
var timeoutFunction = function() {
return function() {
console.log(x)
}
}
setTimeout(timeoutFunction(), 1)
}
var x = 10
This does return only 10. This implies the callbacks are all called after the for-loop is executed? And why do they only conform to the parent scope of the for-loop once the variable is initialised after execution of the for-loop? Am I missing something?
I know how make this example working with
for (var x = 0; x < 5; x++) {
var timeoutFunction = function(x) {
return function() {
console.log(x)
}
}
setTimeout(timeoutFunction(x), 1)
}
Yet, I really wonder what is missing...
Note that specifying 1 as the delay value will not actually cause the function to execute after 1 millisecond. The fastest the function could execute is roughly 9 milliseconds (and that's based on the internals of the browser), but in reality, it can't run the function until there is no other code running.
As for the unexpected output, you are experiencing this behavior because the timeoutFunction includes a reference to the x variable that is declared in a higher scope. This causes a closure to be created around the x variable, such that each time the function runs it does not get a copy of x for itself, but it is sharing the x value because it is declared in a higher scope. This is the classic side effect of closures.
There are a few ways to adjust the syntax to fix the issue...
Make a copy of x and let each function use its own copy by passing x into the function. When you pass a primitive type (boolean, number, string) a copy of the data is created and that's what is passed. This breaks the dependence on the shared x scope. Your last example does this:
for (var x = 0; x < 5; x++) {
var timeoutFunction = function(x) {
return function() {
console.log(x)
}
}
// Because you are passing x into the function, a copy of x will be made for the
// function that is returned, that copy will be independent of x and a copy will
// be made upon each loop iteration.
setTimeout(timeoutFunction(x), 1)
}
Another example that does the same thing would be needed if your timeout function wasn't returning another function (because there would be no function to pass the value to). So, this example creates an extra function:
for (var x = 0; x < 5; x++) {
// This time there is no nested function that will be returned,
function timeoutFunction(i) {
console.log(i);
}
// If we create an "Immediately Invoked Funtion Expression" (IIFE),
// we can have it pass a copy of x into the function it invokes, thus
// creating a copy that will be in a different scope than x.
(function(i){
setTimeout(function(){
timeoutFunction(i); // i is now a copy of x
}, 1);
}(x));
}
If you are working with browsers that support the ECMAScript 2015 standard, you can simply change the var x declaration in your loop to let x, so that x gets block level scope upon each iteration of the loop:
// Declaring a variable with let causes the variable to have "block-level"
// scope. In this case the block is the loop's contents and for each iteration of the
// loop. Upon each iteration, a new "x" will be created, so a different scope from
// the old "x" is what's used.
for (let x = 0; x < 5; x++) {
var timeoutFunction = function() {
return function() {
console.log(x)
}
}
setTimeout(timeoutFunction(), 1)
}
You have to create new scope for your function to make it 'remember' value from given iteration:
for (var x = 0; x < 5; x++) {
var timeoutFunction = (function(x) {
return function() {
console.log(x)
}
})(x)
setTimeout(timeoutFunction(), 1)
}
Another solution is to use ES2015 let:
for (let x = 0; x < 5; x++) {
var timeoutFunction = function() {
console.log(x)
}
setTimeout(timeoutFunction(), 1)
}
use this snippet
for(let x = 0; x < 5; x++) {
var timeoutFunction = function() {
console.log(x);
};
setTimeout(timeoutFunction, 1);
};
console.log('For loop completed');
JavaScript is not multi threaded so with your code the timeoutFunction will execute after the for loop is completed since you are using the global variable (with respect to timeoutFunction context) the final result is printed

scriptProcessorNode.onaudioprocess not able to access global variables

I am building class around a scriptProcessorNode oscillator. I have wrapped my onaudioprocess event handler in a function Gendy.prototype.process. I can access global variables and functions from within this wrapper function, but they are not accessible from within the onaudioprocess function.
I devised a work around for the properties, to redefine them in the wrapper function, but this doesn't work when trying to call another method, a random walk method, with this.walk().
Here is my code:
Gendy.prototype.process = function(){
var point = 0;
var index = 0;
var y = 0;
var breakpoint = this.breakpoint;
var freq = this.freq;
var walk = this.walk();
this.scriptNode.onaudioprocess = function(audioProcessingEvent){
var outputBuffer = audioProcessingEvent.outputBuffer;
var outputData = outputBuffer.getChannelData(0);
for(var j = 0; j < outputData.length;j++){
// linearly interpolate between the new breakpoint positions
// get the interp point by comparing index to the x distance
var lerp = (index - breakpoint[point].x) / (breakpoint[point+1].x - breakpoint[point].x);
y = lerp * (breakpoint[point+1].y - breakpoint[point].y) + breakpoint[point].y;
if(point < breakpoint.length && index >= breakpoint[point+1].x) {
point++;
}
outputData[j] = y;
index+=freq;
if(index >= breakpoint[breakpoint.length-1].x){
index = 0;
point = 0;
walk();
}
}
}
}
This makes sound, but returns the errors:
Uncaught TypeError: walk is not a function
for few lines and then
Uncaught TypeError: undefined is not a function
forever.
Is this a bug with the scriptProcessorNode? Any insight would be appreciated!
no bug in scriptProcessorNode, the issue is the below line:
this.scriptNode.onaudioprocess = function(audioProcessingEvent){
the this varible inside the onaudioprocess would refer to this.scriptNode object by default, you can handle it in one of two ways:
Use bind( as you have done in your answer):
this.scriptNode.onaudioprocess = function(audioProcessingEvent){
...
}.bind(this)
use a local variable to hold the value of this, and use that local variable in place of this:
var self = this;
this.scriptNode.onaudioprocess = function(audioProcessingEvent){
...
I was able to access this from within the onaudioprocess function by attaching .bind(this) to it.
Here is the code:
Gendy.prototype.process = function(){
this.scriptNode.onaudioprocess = function(audioProcessingEvent){
var outputBuffer = audioProcessingEvent.outputBuffer;
var outputData = outputBuffer.getChannelData(0);
for(var j = 0; j < outputData.length;j++){
// linearly interpolate between the new breakpoint positions
// get the interp point by comparing index to the x distance
var lerp = (this.index - this.breakpoint[this.point].x) / (this.breakpoint[this.point+1].x - this.breakpoint[this.point].x);
this.y = lerp * (this.breakpoint[this.point+1].y - this.breakpoint[this.point].y) + this.breakpoint[this.point].y;
if(this.point < this.breakpoint.length && this.index >= this.breakpoint[this.point+1].x) {
this.point++;
}
outputData[j] = this.y;
this.index+=this.freq;
if(this.index >= this.breakpoint[this.breakpoint.length-1].x){
this.index = 0;
this.point = 0;
this.walk();
}
}
}.bind(this);
}

Possible to scope a javascript variable to a function and that function's recursive calls to itself?

I am in a situation where I have a loop that is calling a function. The function will make recursive calls to itself once called.
Is there a way that I can scope a variable to the function and the chain of recursive calls generated from the first call?
Something like this:
for(var i=0;i<100;i++)
{
myFunction();
}
function myFunction()
{
var someNumber = 200;
someNumber -= 10;
if( someNumber > 0)
{
myFunction();
}
}
where at the second iteration of the first call to someNumber would be 190 and not 200. Is this possible to accomplish?
If there is anything confusing here, please let me know.
Yes, use an inner function to do the recursion:
for (var i = 0; i < 100; i++)
{
myFunction();
}
function myFunction()
{
var someNumber = 200;
(function innerFunction()
{
someNumber -= 10;
if( someNumber > 0)
{
innerFunction();
}
})();
};
Note, you have a syntax error. Your while needs to be for.
Edit: Perhaps your real code is different and calls for a recursive function, but your example would be much simpler by just using a loop:
function myFunction()
{
for (var someNumber = 200; someNumber > 0; someNumber -= 10)
{
}
};
while(var i=0;i<100;i++)
{
myFunction(200);
}
function myFunction(someNumber)
{
someNumber -= 10;
if( someNumber > 0)
{
myFunction(someNumber);
}
}
Yes and no--you should be able to accomplish the task by passing the value of the variable in as a parameter of myFunction. The first call will need to set the starting value, then pass it along for future invocations to modify.
while(var i=0;i<100;i++)
{
myFunction();
}
function myFunction(seed) {
if (seed == undefined)
{
seed = 200;
}
alert(seed);
var newSeed = seed - 50;
if (seed > 0)
{
myFunction(newSeed);
}
};
You want a closure. Well, you might not want it, but it will do what you are asking.
(function() {
var someNumber=200;
myFunction=function() {
someNumber-=10;
if (someNumber > 0) {
myFunction();
}
}
})();
But properly passing parameters is probably a better idea.
I think using objects would be the way to go if you want to do something where you are actually scoping variables.
function myObject(_someNumber) {
var someNumber = _someNumber;
this.myFunction = function() {
this.someNumber -= 10;
if(this.someNumber > 0)
{
this.myFunction(this.someNumber);
}
}
}
for(var i=0;i<100;i++)
{
new myObject().myFunction(someNumber);
}

Categories

Resources