I'm trying to find a good way to take a string as input for a conditional statement so that I can check against a list of conditions by iterating through an array of them. Basically, I'm wondering if I could do something like this:
// Would check if foo is equal to one, bar is true, and et is a string containing 'cetera'
var conditions = ["foo==1","bar==true","bar","et=='cetera'"];
for (var i=0;i<conditions.length;i++) {
if (conditions[i]) { console.log("Do stuff..."); }
}
I've thought of eval, but I wonder if it'd be a security risk. The files this code is in don't use PHP or any server software, but the host it runs on does have server software, and I don't know if it should be avoided.
Just drop the strings.
var conditions = [foo == 1, bar == true, bar, et == 'cetera'];
for (var i=0;i<conditions.length;i++) {
if (conditions[i]) {
console.log("Do stuff...");
}
}
This will populate conditions with a bunch of boolean values. You can then loop over it to see if any of them are true.
Edit: This will print "Do stuff..." every time a condition is true. So if foo == 1 is true and et == "cetera", then "Do stuff" will be printed twice. If that isn't what you want, then define an any function like this:
function any(arr) {
for (var i = 0; i < arr.length; ++i) if (arr[i]) return true;
return false;
}
You can then use if (any(conditions)) console.log("Do something...");
Edit 2: If you initialize conditions way before you are checking, (and values might change) wrap each one in a function (although it is a lot more typing). So for example:
var conditions = [
function() { return foo == 1; },
function() { return bar == true; }
// and so on...
];
Similarly, you would have to change if (conditions[i]) { console.log("Do stuff..."); } to if (conditions[i]()) { console.log("Do stuff..."); }
Related
I am trying to create a loop to include an else statement. It works perfectly with the if statement as below but when trying to put in the else statment it either shows nothing or creates 6 loops. Im assuming I am putting the else statement in the wrong place. Can someone please explain to me a) where to put the else statement and b) the nesting criteria of the ending curly braces inside a function
Heres what ive got and it works perfectly until i place the else statement in. thanks
var sports = ["golf", "cricket", "tennis", "badminton", "squash"];
function checkSport(sportToCheck) {
for (var i = 0; i <= sports.length; i++) {
if (sportToCheck == sports[i]) {
alert("yes we offer that sport");
}
}
}
checkSport("tennis")
Based on your variable names, I guess you don't have to use else in this context but you would like to end the loop/function as soon as the sport is found:
function checkSport(sportToCheck) {
for (var i = 0; i <= sports.length; i++) {
if (sportToCheck == sports[i]) {
alert("yes we offer that sport");
return; // stop the execution of the function
} else {
console.log("Do nothing so you don't need this else statement.");
}
}
alert("No we don't offer that sport"); // If the loop ends and cannot find any match
}
Because your function is check() and to respect Do One Thing rule, it's better to return true or false.
There are many ways to solve your issue but I prefer find().
var sports = ["golf", "cricket", "tennis", "badminton", "squash"];
function checkSport(sportToCheck) {
return sportToCheck === sports.find((sport) => sport === sportToCheck);
}
console.log(checkSport("football")); // Expect : false
console.log(checkSport("tennis")); // Expect : true
If you want to improve #Hangindev answer you can do this:
for (sport of sports) {
true === (sportToCheck === sport) && alert("yes we offer that sport");
}
No need for else statements. Simply run through each possible value in the sports array, and use the return statement to pause further script execution within that function.
The function returns either true or false depending on whether the string is inside the sports array.
var sports = ["golf", "cricket", "tennis", "badminton", "squash"];
function checkSport(sportToCheck) {
for (var i = 0; i <= sports.length; i++) {
if (sportToCheck == sports[i]) {
alert("yes we offer that sport");
return true;
}
if (i == sports.length) {
alert("sorry we do not offer this sport");
return false;
}
}
}
checkSport("tennis")
You could use this for something like:
if (checkSport("tennis")) {
// sport exists
} else {
// sport does not exist
}
I have an object which stores department hierarchy. Each department might have sub department as well. I am trying to loop to check all department and also sub(child) department properties are Open.
However, whenever I hit recursive call, it only iterates once and jump directly to return true, even though there are still some items which has not checked in the loop yet.
validateDepartment(departmentHierarchy: any) {
for (let dept of departmentHierarchy.children) {
if (dept!= undefined && dept!= null) {
if (dept.instance.status == "Open")
{
continue
}
else
{
if (dept.children != undefined && dept.children != null) {
this.validateDepartment(dept);
}
else {
return false
}
}
}
}
return true
}
Not part of any answer, but it helps to only write the code that "does" things, rather than having lots of code that does "what the code would already do anyway", such as calling a continue when the iteration code is a single if/else. We can rewrite your code to this, and have something easier to work with:
validateDepartment(tree: any) {
// step 1: do any validation of the top node
if (!validateTopNodeOnly(tree)) {
// this is a stop condition.
return false;
}
if (!tree.children) {
// this is also a stop condition, but for a different reason.
// a department without children should not _necessarily_ be invalid.
return true? return false? probably return true since the node itself is fine.
}
if (tree.instance && tree.instance.status !== "open") {
// and this is a third condition, but for yet another reason.
// I'm guessing this is also not "invalid", just means we shouldn't recurse.
return true? return false? probably return true as well.
}
// Then, get all (non-falsey) children,
let children = tree.children.filter(e => e);
// and iterate over them:
for (let e of children) {
let result = this.validateDepartment(e);
// cut your run short if validation fails
if (result === false) {
return false;
}
}
// and this is the expected stop condition for a normal run.
return true;
}
But using true/false is incredibly naive and won't tell you anything about where validation failed, so you'll want to work in "what failed", typically by returning a reference to the actual "thing that's getting validated" so that if your function returns true, all is well, and it returns something !== true then you know it failed, and the thing it returned is the department where things went wrong.
Also note that by using an early return on validation failure, you're missing out on information: instead it's way better to use .map() and construct a running tally of all deparments that pass/fail validation, so that you return an array in which either result.every(e => (e===true)) is true, or is false, in which case result.filter(e => (e!==true)) gives you the set of every single failed department.
isopen = this.validateDepartment(this.departmentHierarchy);
validateDepartment(dept: any): boolean {
let result=(dept.instance.status == "Open");
if (result) {
if (dept.children) {
dept.children.forEach(x => {
result = result && this.validateDepartment(x)
})
}
}
return result;
}
I am fairly new to JavaScript and I have a question regarding how to optimise if statements.
I will show you two scenarios.
//first
var number = 10;
var calculationOneResult = functionOne(number);
var calculationTwoResult = functionTwo(number);
if (calculationOneResult === true) {
//stuff
} else if (calculationTwoResult === true) {
//more stuffs
}
//second
var number = 10;
if (functionOne(number) === true) {
//stuff
} else if (functionTwo(number) === true) {
//more stuffs
}
Here is my question:
In the first scenario, I am calculating two times.
In the second one, if the first function returns true, will it calculate the second elseif statement or will it skip it after doing the stuff ?
The following code:
if(statement1) {
// stuff
} else if(statement2) {
// other stuff
}
is equivalent to
if(statement1) {
// stuff
} else {
if(statement2) {
// other stuff
}
}
as there is no elseif in JavaScript - see documentation.
So the answer is any function in statement2 will be simply skipped.
Nothing in an else clause executes if the if expression tests as true, so the second version of your code will definitely save a function call in such cases.
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;
}
I need to pass certain parameters into a function and have that function pull from an array based on the arguments passed to it. It's hard to explain, so I'll show you what I'm trying to do.
function SearchDeck(deck,...){
var tryagain = true;
do{
if(deck[0].property == value){
//do something;
tryagain = false;
}
else{
deck.splice(0,1);
}
}
while(tryagain);
}
There are multiple decks to look in, the proper deck will be passed in. I want to always be drawing off the top of the deck (index 0 of the array). I need to draw continuously until I find a card that matches what I'm after. I splice out the 0 index if it doesn't match. What I'm after is dynamic, varying across the properties or even the operators I would use.
Some examples of if statements I would have are...
deck[0].color == "orange"
deck[0].value >= 5
deck[0].value < -4
I could make multiple functions or have the function fork based on an argument, but that doesn't seem like the best way to go about this.
If I'm understanding this correctly, you want the behavior of the if(deck[0].property == value) to be different for each invocation of the SearchDeck(...) function?
My recommendation would be to pass in a function:
function SearchDeck(deck, validationFunction, ...){
var tryagain = true;
do{
if(validationFunction(deck[0])){
//do something;
tryagain = false;
}
else{
deck.splice(0,1);
}
}
while(tryagain);
}
Then when you call the code, you can do:
SearchDeck(deck, function(firstCard) { return firstCard.color == "orange" }, ...);
SearchDeck(deck, function(firstCard) { return firstCard.value >= 5 }, ...);
SearchDeck(deck, function(firstCard) { return firstCard.value < -4 }, ...);
Or, if the cases you're looking for might be reused, it might also be cleaner to make those named functions:
function validateColor(firstCard) {
return firstCard.color == "orange";
}
function validateHighValue(firstCard) {
return firstCard.value >= 5;
}
function validateLowValue(firstCard) {
return firstCard.value < -4;
}
SearchDeck(deck, validateColor, ...);
SearchDeck(deck, validateHighValue, ...);
SearchDeck(deck, validateLowValue, ...);
It sounds like you may be interested in the typeof operator:
if (typeof deck == 'object') { ... }
if (typeof deck[0].color == 'string') { ... }
if (typeof deck[0].value == 'number') { ... }
Alternatively:
if (deck[0].hasOwnProperty('color')) { ... }
This is what I came up with. You need to push the way of check (either "== 'oragne'" or "<3") as string.
function searchDeck() {
var deck = Array.prototype.slice.call(arguments, 1),
tryagain = true,
string = deck[deck.length - 1];
deck.pop();
while (tryagain) {
if (eval('deck[0].property' + string)) {
//do something;
alert('card found');
tryagain = false;
} else {
deck.splice(0, 1);
}
}
}
Hope this is what you wanted ;)
Here is a working jsfiddle example, of course there might be a more elegant way, this is just what I came up with. Note that eval can be dangerous, so you should be carefull if user picks what the test will be (the string pushed into the array).