Incremental while loop becomes infinite - javascript

I'm trying to create a new folder with an ascending number on the end if a folder already exists, but I end up in an infinite loop
var i=1;
while (myFolder.exists == true) {
var myFolder = new Folder(wf+"/"+curFile+"_folder"+i)
i++;
};
Any help would be appreciated.

It looks like myFolder.exists is a method, not a property, so you have to call it:
while (myFolder.exists()) {
var myFolder = new Folder(wf + "/" + curFile + "_folder" + i);
i++;
};
Otherwise, you would be evaluating the method itself, which is indeed always true in a boolean context.
Note in passing that redefining myFolder inside the loop is probably not the problem here. Loops in Javascript share the same scope as the enclosing code, and the variable will be hoisted to the start of that scope. As jdwire says, it can be undefined initially, but then you would receive an error instead of triggering an infinite loop.

Related

Keep track of current line number in eval

I'm running some code using eval that will change a $scope object called variables.
Here's my watcher:
$scope.$watch(function () {
return $scope.variables;
}, function (variables) {
console.log('changed!');
}, true);
Here's the code I'm running (this is just example code; it could be any arbitrary code I can't anticipate):
eval('$scope.variables.foo = "bar";\n$scope.variables.bar = "foo";');
In this example, the watcher is triggered twice, and gives me the new values. So far so good. What's missing is the information that the first trigger was caused by the first line in the eval call, and the second one on the second line (note the \n in the eval call denoting a new line number).
Is there a way to achieve this using Angular or just plain JavaScript? I have looked into tools like https://github.com/stacktracejs/stacktrace.js but they don't seem to do the trick.
Just to be clear, I'm not looking for line numbers for when errors are thrown. I need to keep track of which line the eval statement is currently on when the watcher's callback is triggered, so that I can associate that line number with the change that has been made to the object I'm watching.
You could split your input string by \n and insert new statements keeping track of the line numbers
var s = '$scope.variables.foo = "bar";\n$scope.variables.bar = "foo";\n'
var arr = s.split(/\n/);
var out = [];
for (var i = 0; i < arr.length; i++) {
out.push("console.log('current line: " + i + "');");
out.push(arr[i]);
}
out = out.join('\n');
console.log(out);
document.write('<pre>' + out + '</pre>');
You can replace the console.log() by what you want, a call to another function, a debug call...

Confusion around closure/scope

Today while working with some JS I had a bug in my code. I was able to resolve it but I don't really understand why the change I made works. All I can guess is that it comes down to either closure or variable scope.
I was trying to build up a nested hash of arrays like so:
var maxNumberOfPairs = 2;
var container = {};
var pairsHash = {};
$.each(["nurse", "doctor", "janitor", "chef", "surgeon"], function(index, role) {
for(var i = 0; i < maxNumberOfPairs; i++){
var pairIdSubString = "attribute_" + i + "_" + role;
pairsHash["attribute_" + i] = [pairIdSubString + "_night", pairIdSubString + "_day"];
}
container [role] = pairsHash;
});
If you run this you get a nice nested output inside container but when you look at each array in the hash you get a weird behaviour with the string produced.
Each one has the last role in each string like so:
"attribute_0_surgeon_night"
If you log out the variable pairIdSubString it correctly has the role in the string, but as soon as this is added to pairHash it just uses the last element in the $.each array.
I was able to fix it by moving pairsHash inside the $.each but outside the for loop.
Can anyone explain to my why the output was different after moving it inside the each?
Thanks
It actually has to do with reference vs value. When its outside the each you are operating on the same object over and over so every time you set it to the container you are just setting a reference to the same object that is constantly changing. So every reference in container after the loop is the last state of the pairsHash because they all point to the same object.
When you put the pairsHash in the each it is reinitialized every time so they all point to different memory addresses. Not the same one since a new one is created every loop.
To further clarify all objects are just references to a memory address In JavaScript so in order to get new one you need to initialize or to pass by value to a function clone it.

Calculation returns NaN

I'm trying to create a page that allows for the multiple upload of images, this requires different name attributes. To achieve this, I'm using JS to add one the variable i giving a number.
The below code returns NaN, I'm not too sure why?
$('document').ready(function() {
var i = 1;
$('#new-dialogue').click(function() {
var i = i + 1;
$('.create-upload').append('<div class="upload"><input type="file" name="image' + i + '"/></div>');
});
});
Remove the second var.
What your current code is saying, is what when new-dialogue is clicked, it should create a variable called i and set it to i+1... but because i hasn't been defined yet in this scope you are doing undefined + 1, which is NaN.
Removing the second var will cause the click function to get the i variable from the containing scope, which is what you want it to do. You can then just have i++ to increment it as needed.
That said, you could just make your life easier by using:
<input type="file" name="image[]" />
Because on the server side, you will then have an array of uploaded files ;)
Instead of
var i = i + 1;
Just do
i++;
You need to increment already declared variable, not re-declare it again.
When you redeclared i local to the callback, your function got its own local copy of i that had yet to receive a value. So var i = i + 1; is basically var i = undefined + 1;, which evaluates to NaN.
Get rid of the var to fix this.

how could I pass closure problems in order to increment a global var

I have a simple goal, I would like to increment a variable but I'm facing the closure problem. I've read why this s happening here How do JavaScript closures work?
But I can't find the solution to my problem :/
let's assume this part of code I took from the link.
function say667() {
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() { alert(num); //incrementation
}
num++;
return sayAlert;
}
I would like to increment num within the function and to keep the changes to num.
How could I do that ?
Here is the JsFiddle where I have my problem, I can't figure out how to increment my totalSize and keep it.
http://jsfiddle.net/knLbv/2/
I don't want a local variable that ends up with closure.
From your fiddle, I guess the problem is a mix of closure (totalSize should be outside of the loop) and query.exec being asynchronous (this one can be verified with some console.log).
What you seem to need is some kind of control flow, something like async.reduce
function say667() {
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() { alert(num++); //incrementation
}
return sayAlert;
}
var inscrese = say667();
so if you want to increase by one just call increase();
If all other solutions fail, then make num an array: var num = [666], then increment it's first element: num[0]++.

javascript function in a for loop not causing crashing browser

I'm new at coding and am trying to figure out why this doesn't work. the function works fine I'm assuming there is a fundamental flaw in the sumArray function that is not processing
// SET UP FUNCTIONS FOR LATER USE
// sumArray - takes all values within an array and adds them
var sumArray = function(x){
var sum = 0;
for(i=0;i<x.length;i++) {
sum += parseInt(x[i]);
};
return sum;
};
// create an array and use sumArray function inside of a loop.
// This works
var arrayTest = new Array(1,2,3,4,5,6,7,8,9,10);
document.write (sumArray(arrayTest);
// This crashes the browser
for(i=0;i<10;i++){
document.write("<br/>" + sumArray(arrayTest) + "<br/>");
};
Thanks in advance for any insight.
You need to declare "i" with var:
for(var i=0;i<10;i++){
in both loops. If you don't do that, there's just one global "i" clobbered by both loops.
Just before the second loop, you're missing a ).
document.write (sumArray(arrayTest) ); // <-- right here
Additionally, be very careful with document.write. If it runs while the document is loading, you'll probably be alright. Be sure you don't use it after the doc has loaded.

Categories