My Inner loop seems to work fine, but once the inner loop is complete i expect the first loop to start again but it doesn't and it's not clear to me why...
if(search)
{
// loop through Revenue Arrangements
for (var x = 0; search != null && x < search.length; x++)
{
var revenue_arrangement = nlapiLoadRecord('revenuearrangement', search[x].getValue(columns[0]));
nlapiLogExecution('DEBUG', 'Revenue Arrangement Internal ID', search[x].getValue(columns[0]));
var count = revenue_arrangement.getLineItemCount('revenueelement');
for (var x = 1; x <= count; x++)
{
var rev_element_id = revenue_arrangement.getLineItemValue('revenueelement', 'transactionline', x);
if(rev_element_id)
{
nlapiLogExecution('DEBUG', 'Element Internal ID', rev_element_id);
}
}
nlapiLogExecution('DEBUG', 'End of Inner Loop);
}
}
your both loops (inner and outer) are using the same variable as counter (x)
Use different counter variables for both
if(search)
{
// loop through Revenue Arrangements
for (var x = 0; search != null && x < search.length; x++)
{
var revenue_arrangement = nlapiLoadRecord('revenuearrangement', search[x].getValue(columns[0]));
nlapiLogExecution('DEBUG', 'Revenue Arrangement Internal ID', search[x].getValue(columns[0]));
var count = revenue_arrangement.getLineItemCount('revenueelement');
for (var y = 1; y <= count; y++)
{
var rev_element_id = revenue_arrangement.getLineItemValue('revenueelement', 'transactionline', y);
if(rev_element_id)
{
nlapiLogExecution('DEBUG', 'Element Internal ID', rev_element_id);
}
}
nlapiLogExecution('DEBUG', 'End of Inner Loop);
}
}
You're reusing the x variable and the nested iteration affects the outer one. This was stated clearly in other answer, but let's extend this to point to two aspects of javascript you might be not aware of, but you should:
Javascript uses block operators {} but it does not implement block
scope. This means that a for loop does not create a new variable
scope. This is significant if you come from c/c++ background.
See more:
http://doctrina.org/JavaScript:Why-Understanding-Scope-And-Closures-Matter.html
(also see for closures, that is how outer scope affects nested function scopes).
Javascript hoists variable declarations to the beginning of a
function scope. This means both of var x are effectively declared
in the very beginning of the snippet included in the question (or
possibly even earlier).
See more:
http://www.w3schools.com/js/js_hoisting.asp
Extra var hoisting example which shows how bizzare can be its effects: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
The above means that your code (simplified) of this:
var search = ["a","b","c","d"], count;
if(true) {
for (var x = 0; x < search.length; x++){
count = 2;
for (var x = 1; x <= count; x++){
console.log("innner", x)
}
console.log("outer", x)
}
}
is the same as this:
var search = ["a","b","c","d"], count, x = 1;
if(true) {
for (; x < search.length; x++){
count = 2;
for (; x <= count; x++){
console.log("innner", x)
}
console.log("outer", x)
}
}
That means you don't only have two loops that affect each other. You're also ignoring the 0 element of the first array (the var x = 1 in nested loop overrides var x = 0 in the outer).
Both snippets will output:
innner 1
innner 2
outer 3
Related
So, I have an array and I wanted to check if some values are the same or 0. And if not, than it should call the function "end" and stop, but instead it never stops and keeps calling the function "end".
function test() {
loop:
for (var x = 0; x < arr.length; x++) {
if (arr[x] === 0) break;
else if (x + 1 === arr.length) {
for (var x = 0; x < 4; x++) {
for (var y = 0; y < 3; y++) {
if (arr[4 + x + y * 4] === arr[x + y * 4]) break loop;
if (arr[11 - x - y * 4] === arr[15 - x - y * 4]) break loop;
}
}
for (var y = 0; y < 4; y++) {
for (var x = 0; x < 3; x++) {
if (arr[1 + x + y * 4] === arr[x + y * 4]) break loop;
if (arr[14 - x - y * 4] === arr[15 - x - y * 4]) break loop;
}
}
end();
}
}
}
Edit: found the problem, I used the x variable twice.
Sorry for wasting your time
for starters: declare loop iteration variables with let instead of var - variables declared with var are scoped to the function (while let/const are scoped to the code block/loop)
See the following code, to see how let/var result in different outputs
for (var x = 0; x < 3; x++) {
console.log("outer loop var" + x)
for (var x = 0; x < 2; x++) {
console.log("inner loop var" + x)
}
}
for (let x = 0; x < 3; x++) {
console.log("outer loop let" + x)
for (let x = 0; x < 2; x++) {
console.log("inner loop let" + x)
}
}
in the loops with var both loops use the same variable - so the loop is exited after only 1 iteration of the outer loop (+ 2 of the inner one) (since x reaches 3 because both the inner and outer loop use the same variable to iterate - and therefor also add to the same variable after each iteration - so the inner loop is exited, because x reaches 2, then the first iteration of the outer loop ends and 1 is added, which means x becomes 3 and the loop is exited)
int the loops with let both loops each use their own variable, so we get our intended 3 iterations of the outer loop and 3 * 2 for our inner loop.
Could you show matriz data? And explain better what is the requeriment of your problem? Maybe we could find alternatives or apply other logic.
Why doesn't "i" always equal zero? Do subsequent iterations of the loop skip the var declaration? I know that at the end of the first iteration i = 1 but when it goes through subsequently does the var declaration not reset i = 0?
When I run the function with args it all works but I just don't know why the var declaration doesn't reset if that makes any sense. It would make sense to me if the var "i" was declared outside of the loop.
function multiply(arr, n) {
var product = 1;
for (var i = 0; i < n; i++) {
product *= arr[i];
}
return product;
}
The first section of a for loop declaration is (for the most part) only run once, at the very beginning of the loop. Your code is equivalent to:
function multiply(arr, n) {
var product = 1;
var i = 0;
for (; i < n; i++) {
product *= arr[i];
}
return product;
}
Which is equivalent to:
function multiply(arr, n) {
var product = 1;
var i = 0;
while (true) {
// for loop body:
product *= arr[i];
// for loop declaration part:
i++;
if (!(i < n)) break;
}
return product;
}
So, i is only assigned 0 once, at the very beginning.
I qualified the above with for the most part because, when the behavior is somewhat stranger when a variable is declared with let, and let has block scope, not function scope - with let, every iteration creates a separate binding for the variable name. (but that's not worth worrying about in your case - it's only really something that needs to be considered when the for loop uses the variable asynchronously)
I've run into this error multiple times now, and wondering if there's a way to have the code auto control for it?
var length = some_array.length
for (var i = 0; i < length; i ++) {
someMethod(some_array[i].name)
}
function someMethod(name) {
var length = other_array.length
for (var i = 0; i < length; i ++ ) {
// some code
}
}
The code above doesn't run properly because the inner i and length carry over to the outer level code. So to actually make it work, I have to manually set different variables to manage the scoping. I.e., something like the below works:
var length = some_array.length
for (var i = 0; i < length; i ++) {
someMethod(some_array[i].name)
}
function someMethod(name) {
var s_length = other_array.s_length
for (var s_i = 0; s_i < length; s_i ++ ) {
// some code
}
}
But of course, it's hard to always remember when an inner function has another loop in it. Wondering if there's a way to control it so that loop variables are always only constrained to THAT loop itself.
This is why let keyword is a better option than var- it keeps the scope to just the function or method that calls it.
The following snippet consoles -
0 / test 1 / 0 / test a
0 / test 1 / 1 / test b
1 / test 2 / 0 / test a
1 / test 2 / 1 / test b
ie: for each item of some_array - it calls someMethod and consoles the name of the first array as well as each iteration of the second array (other_array).
let some_array=[{id: '1', name: 'test 1'},{id: '2', name: 'test 2'}];
let other_array=[{id: 'a', name: 'test a'},{id: 'b', name: 'test b'}];
let length = some_array.length;
for (let i = 0; i < length; i ++) {
someMethod(i, some_array[i].name)
}
function someMethod(index, name) {
let length = other_array.length
for (let i = 0; i < length; i ++ ) {
console.log(index + ' / ' + name + ' / ' + i + ' / ' + other_array[i].name);
}
}
SCOPE
In JavaScript there are two types of scope:
Local scope
Global scope
JavaScript has function scope: Each function creates a new scope.
let allows you to declare variables that are limited in scope to the block.
Notice how var create a property on the global object but let is undefined.
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
Let's try it with your code.
let some_array = [{ name: 'Angel' }, { name: 'James' }]
let other_array = ['0','1'];
//let i is declared local
for (let i = 0; i < some_array.length; i++) {
someMethod(some_array[i].name) //"let" some_array variable is required here to the local "for loop" scope.
}
function someMethod(name) {
//let i is declared local here again so it's considered a new variable i.
for (let i = 0; i < some_array.length; i++) {
console.log(name)
}
}
For more examples about scope in Javascript
I have a javascript function as below :
function modifyx(xvalue) {
val = 1;
for (x = 0; x < 10; x++) {
val = val + 1;
}
return val;
}
And the main snippet passes a variable named x to the above function as below:
for (x = 0; x < 10; x++) {
console.log(modifyx(x));
}
The expected output should be "11" printed 10 times but instead it prints one time. The function call changes the value of x eventhough i am not modifying the passed value. The x inside the function has it's own scope. Yet it gets modified. Any help on this would be highly appreciated.
The variable x in your code is global. When your method modifyx(xvalue) returns for the first time the value of x is already 11 which is used in the for loop for the second iteration. Thus it fails to execute the method further.
Use let x in the declaration in for (x = 0; x < 10; x++) to create a unique execution environment.
function modifyx(xvalue) {
val = 1;
for (x = 0; x < 10; x++) {
val = val + 1;
}
return val;
}
for (let x = 0; x < 10; x++) {
console.log(modifyx(x));
}
Just put var in both places in for loop
function modifyx(xvalue) {
val = 1;
for (var x = 0; x < 10; x++) {
val = val + 1;
}
return val;
}
for (var x = 0; x < 10; x++) {
console.log(modifyx(x));
}
because its taking x as global variable in your code.
MDSN documentation on variable scopes in JavaScript:
JavaScript has two scopes: global and local. A variable that is
declared outside a function definition is a global variable, and its
value is accessible and modifiable throughout your program. A variable
that is declared inside a function definition is local. It is created
and destroyed every time the function is executed
When using the var keyword, the variable declaration is pulled to the top of it's scope (the function).
In your example code, you are using a for loop without defining var x. When you use for (x = 0..., the browser assumes you meant for (var x = 0... so it creates a global variable called x.
Inside your function modifyx, you are setting the global x to 11 by the end of it's execution. This causes the outer loop to run only once because x is no longer less than 10 after the first loop.
Here is an example of what's going on with comments:
function modifyx(xvalue) {
val = 1;
for (x = 0; x < 10; x++) { // sets the global 'x' to 11 after loop finishes
val = val + 1;
}
return val;
}
// 'x' is being defined as a global variable
for (x = 0; x < 10; x++) {
console.log(modifyx(x)); // modifyx sets 'x' to 11
// x is now 11, loop will now quit
}
A simple solution is to use the let keyword in both loops, thus restricting the scope.
for (let x = 0; x < 10; x++) { ... }
I have a for loop but it gets executed once where it should execute two times.
The $appointments variable holds the returned data from an ajax call. When I console.log($appointments.length) I get two which is correct but the iteration happens only once and I can't figure out why.
for (var i = 0; i < $appointments.length; i+=1) {
var rangeStart_hour = $appointments[i].timerange.substring(0, 2);
var rangeStart_minutes = $appointments[i].timerange.substring(3, 5);
var rangeEnd_hour = $appointments[i].timerange.substring(11, 13);
var rangeEnd_minutes = $appointments[i].timerange.substring(14, 16);
var rangeS = rangeStart_hour + rangeStart_minutes;
var rangeE = rangeEnd_hour + rangeEnd_minutes;
var rangeStart = parseInt(rangeS);
var rangeEnd = parseInt(rangeE);
var range=0;
if(parseInt(rangeStart_hour) == 12){
if(parseInt(rangeStart_minutes) == 0){
range = rangeEnd - 0;
}else{
range = rangeEnd - (parseInt(rangeStart_minutes)+20);
}
}else{
if(parseInt(rangeStart_minutes) == 30 && parseInt(rangeEnd_minutes) == 0){
// if start time 1:30 ,end time 3:00
range = (rangeEnd - (rangeStart + 20)); // 300 - 150 = 150
}else if(parseInt(rangeStart_minutes) == 0 && parseInt(rangeEnd_minutes) == 30){
range = ((rangeEnd+20) - rangeStart);
}else{
range = rangeEnd - rangeStart;
}
}
console.log(range);
for(var i=1; i<(range/50); i++){
$("a[data-time='"+(rangeStart)+"']").addClass('time');
rangeStart += 50;
};
};
This structure seems like a bad idea:
for (var i = 0; i < $appointments.length; i += 1) {
//...
for (var i = 1; i < (range/50); i++){
//...
}
}
You probably want to use different variable names for your nested loop counters.
You reinitialize the variable i in the second for loop, if you change
for(var i=1; i<(range/50); i++){
$("a[data-time='"+(rangeStart)+"']").addClass('time');
rangeStart += 50;
};
to use a different variable, say j it should work fine.
In JavaScript, the scope of variable is function scope. It means that all variable declarations are hoisted to the top of the function.
So, in your case:
for (var i = 0; i < $appointments.length; i += 1) {
...
for (var i = 1; i < (range/50); i++){
...
};
};
equals with
var i; // two variables with the same name are hoisted as the same variable.
for (i = 0; i < $appointments.length; i += 1) {
...
for (i = 1; i < (range/50); i++){
...
};
};
So, at the end of the second loop, "i" will be greater than or equal to range/50. If this value is not less than $appointments.length, the first loop will terminate after the first round.
Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
In your code the "i" variable used twice, So second time initialized value is Incrementing in first for loop. That's why, Condition failed in first for loop and loop is terminating. Change the variable name in second or first for loop then it will be working as you expected