My question is: How can I trigger a break; or continue; for a loop through a function that gets called? The thing is, I do not want to nest all possible conditions within a loop to avoid code complexity. I was thinking about some pseudo example:
var someObjects = [...] //array with some js objects
for (var i = 0; i < someObjects.length; i++) {
var element = someObjects[i];
doSomething(element);
}
function doSomething(object) {
//some code here
if (somethingIsDefined) {
doSomethingElse(object);
}
}
function doSomethingElse(anotherObject) {
//some more code here
if (somethingMatches) {
//here i would like to break the most upper loop
}
}
//someObjects will be processed
I know that it would be possible to introduce for example a boolean variable and check within the loop if it is true or false and depending on that, break; or continue;.But this - even if it is just one line - would increase the nesting. Do you see any possible solutions?
If you are using the Underscore library, which I recommend, you could write the following:
_.any(someObjects, doSomething);
function doSomething(object) {
//some code here
return somethingIsDefined &&
doSomethingElse(object);
}
function doSomethingElse(anotherObject) {
//some more code here
return somethingMatches;
}
Related
Trying to make a function that runs on its own using private variables. Version 1 turned out pretty good, but for it to work I have to input 2 parameters and use
Other things that I've tried are in version 2 and 3 where the variables aren't global, but it'd great if they all were inside the function.
// Independent functions
// description: Attempt to create a function that runs a part of its code
// only once, and later ignores it. The function needs to run without the use of external code (like global variables).
[Update] It finally worked. Huge thanks to ocBiermann, for mentioning that functions in javascript are also objects. Here's how you do it with arrays.
function Ind(x) {
if (Ind.random === undefined) {
sum = [];
Ind.random = 2;
}
if (Ind.random === 2) {
sum.push(x);
x--;
if (x != 0) {
Ind(x);
}
return sum;
}
}
console.log(Ind(10));
// Here's how I did it with switch (The code is longer though).
function Index(start, end) { // 1) Start and end are used as input
switch (start) {
case "Second_run": // 4) Second time running
output = []; // 5) declares output array
start = "Third_run";
Index(start, end)
break;
case "Third_run": // 6) Third time running.
save++;
output.push(save); // 7) The value of save is saved in output
if (save == end) { // 8) Functions is re-executed, conditions met
return output
}
Index(start, end)
break
default: // 2) The function starts here and saves start's value as save
save = start;
start = "Second_run"; // 3) It chages start's value to "Second_run"
Index(start, end)
break;
}
return output
}
console.log(Index(0, 10));
// Here's the first one, but with start and end (same concept with small changes)
function Ind(start, end) {
if (Ind.random === undefined) {
output = [];
Ind.random = 2;
}
if (Ind.random === 2) {
output.push(start);
start++;
if (start <= end) {
Ind(start, end);
}
return output;
}
}
console.log(Ind(10, 15));
It looks like you are trying to make the function avoid executing certain code based on the result of previous executions WITHOUT using global variables or parameters.
Remember that in JavaScript, a function is also an object. This means that a function can have properties, much like the object of a class.
So the nice thing is you can access and set properties each time your function is executed, and then execute the code you want based on that.
Here is a pretty simple example:
function Independent()
{
/*First check if the property has already been defined */
if (Independent.SomeProperty === undefined) {
Independent.SomeProperty = 1;
console.log("This is the first time Independent() is being called");
}
else if (Independent.SomeProperty === 2) {
console.log("This is the second time Independent() is being called");
//Your code here
}
else if (Independent.SomeProperty === 3) {
console.log("This is the third time Independent() is being called");
//Your code here
}
//etc.
Independent.SomeProperty++; //Increment your property here.
}
You could even use a switch statement if your function will be called more than a few times. Or you could make the value wrap around back to 0 after the function has been called a certain number of times. There are many other possibilities as well. It just depends on your specific requirements.
I'm writing some JavaScript (with jQuery) that needs to be more flexible. However, I'm not sure how to approach this. This is my code:
var scrollTop = $(this).scrollTop();
var scrollArr = $('.data').html().split(","); // eg. array is 0,80,240,350,380,630
function doIt() {
if (scrollTop<parseInt(scrollArr[0])) {
//$('.scrollShow img').eq(0).removeClass('h')
}
if (scrollTop>parseInt(scrollArr[0])&&scrollTop<parseInt(scrollArr[1])) {
$('.scrollShow .anim').eq(0).addClass('o01s')
}
if (scrollTop>parseInt(scrollArr[1])&&scrollTop<parseInt(scrollArr[2])) {
$('.scrollShow .anim').eq(1).addClass('o01s')
}
if (scrollTop>parseInt(scrollArr[2])&&scrollTop<parseInt(scrollArr[3])) {
$('.scrollShow .anim').eq(2).addClass('o01s')
}
}
The problem is that the amount of elements in the array (scrollArr) will vary each time the doIt() function is run, so if/else statements are not practical in my opinion. What should I replace them with? The code to be executed would be the same (as the above example - with the number increment) and so a flexible function seems more appropriate. Or am I going about this the wrong way? Any input would be appreciated.
for (var i=0; i<scrollArr.length; i++) {
if(scrollTop>parseInt(scrollArr[i])&&scrollTop<parseInt(scrollArr[i+1]))
{
$('.scrollShow .anim').eq(i).addClass('o01s')
}
}
I'm looking for something simple and straight forward, most of what I've pulled up on stack isn't quite what I need. I have an array that I want to loop through while calling a function after each iteration. What would that look like?
I'm assuming you're having problems with this because of the way closures are handled in Javascript. Douglas Crockford talks about this, in his book, by using the example of a function that assigns a click event handler to an array of nodes. The "intuitive" way is:
var addHandlers=function(nodes){
var i;
for(i=0; i<nodes.length;++i){
nodes[i].onClick= function {
alert (i);
};
}
};
However, this is not correct: each onClick callback will show the same value of i = nodes.length-1. This is because the value of i is not copied, but referenced in each inner function. The better way would be to create a helper function that returns a callback, something along the lines of the following:
var addHandlers = function (nodes) {
var helper = function (i){
return function (e){
alert (i);
}
}
for (int i =0; i<nodes.length();i++){
nodes [i].onClick=helper (i);
}
}
Plus, this allows you to avoid creating a function at each iteration.
var arr = [1,2,3];
for(var i = 0; i < arr.length; i++){
someFunction();
}
If you want to process one elment of the array to be used in an asynchronous funcion and then process the next next element you can do something like this;
function asynchCallback(arrayToProcess,someVar){
console.log("callback called with parameter:",someVar);
processArray(arrayToProcess);
}
function processArray(arr){
if(arr.length===0){
console.log("done");
return;
}
var someVar=tmp.splice(0,1);
setTimeout(function(){
asynchCallback(tmp,someVar[0]);
},100);
}
//send a copy of the array:
processArray([1,2,3].concat());
What is the maximum recursion depth in Google Apps Script scripts? I have a function, match_recurse, which looks like the following pseudocode:
function match_recurse(array) {
for (i=0, i<3, i++) {
var arr2 = array.copy().push(i);
if (is_done(arr2)) break;
match_recurse(arr2);
}
}
(It also returns its results, but I don't want to bloat the question.)
Now, because the execution errored, the execution transcript and the logs were not saved, so I have no way of knowing whether my is_done function is doing its job wrong. I can do a few cases of the problem on paper and check recursion depth, but I don't know what the maximum is supposed to be.
Looking on the web, I saw an article mentioning that IE has a max call stack of 13 if you go through the Window object, but nothing else.
It is 1000, as one can see from here:
function recurse(i) {
var i = i || 1;
try {
recurse(i+1);
} catch (e) {
Logger.log(i);
}
}
The stack depth value is not documented. Executing the following code shows that this value is equal to 1000.
function getStackDepth(curvalue) {
try {
curvalue = getStackDepth(curvalue) + 1;
}
catch(err) {
}
return curvalue;
}
function test() {
var depth = getStackDepth(2);
debugger;
}
I need to wait for an ajax response inside a for loop. If I could I'd simply make a synchronous call instead of asynchronous, but I don't have that level of control: I'm using somebody else's API which in turn calls eBay's Javascript API.
Below are my two functions, actually methods on the same closure/object, with categoryStack and categoryMap in scope for each. In essence I'm trying to recursively build up a map, though I want to use a stack for management, rather than true recursion.
I've tried a few variations on setInterval/setTimeout but I always get one of two results: one iteration of the loop, or an endless loop. Note that m_eBay.getChildCategories specifies the second of the two functions below as a callback, and I have confirmed that I am getting there successfully.
function getChildCategories() {
categoryStack.push(-1);
while (categoryStack.length > 0) {
catId = categoryStack.pop();
m_eBay.getChildCategories({
'success':getChildCategoriesSuccess,
'failure':getChildCategoriesFailure},
{'siteid':0, 'CategoryID':catId, 'IncludeSelector':'ChildCategories'}
);
/*
use response from getChildCategoriesSuccess to reset categoryStack
*/
}
}
function getChildCategoriesSuccess(data){
if (data.categoryCount > 0) {
var categoryObjs = data.categoryArray.category;
for (var i=0, n=categoryObjs.length; i<n; i++) {
var catObj = categoryObjs[i];
if (catObj.categoryID != -1) { //skip root
categoryStack.push(catObj.categoryID);
categoryMap[catObj.categoryName] = catObj.categoryID;
}
}
}
}
Using asynchronous ajax you need to do something like:
function getChildCategories(onload) {
var categoryStack = [-1];
function doNextOrFinish() {
if (categoryStack.length) {
m_eBay.getChildCategories({
'success': function(data) {
if (data.categoryCount > 0) {
var categoryObjs = data.categoryArray.category;
for (var i=0, n=categoryObjs.length; i<n; i++) {
var catObj = categoryObjs[i];
if (catObj.categoryID != -1) { //skip root
categoryStack.push(catObj.categoryID);
categoryMap[catObj.categoryName] = catObj.categoryID;
}
}
}
doNextOrFinish();
},
'failure':getChildCategoriesFailure},
{'siteid':0, 'CategoryID':categoryStack.shift(), 'IncludeSelector':'ChildCategories'}
);
} else {
if (onload) onload();
}
}
doNextOrFinish();
}
Still uses recursion though.
Another solution to this problem is to use Arrows.