I am a newbie when it comes to JavaScript and it was my understanding that using one SWITCH/CASE statements is faster than a whole bunch of IF statements.
However, I want to use a SWITCH/CASE statement with two variables.
My web app has two sliders, each of which have five states. I want the behavior to be based on the states of these two variables. Obviously that is a whole heck of a lot of IF/THEN statements.
One way I thought about doing it was concatenating the two variables into one and then I could SWITCH/CASE that.
Is there a better way of accomplishing a SWITCH/CASE using two variables ?
Thanks !
Yes you can also do:
switch (true) {
case (var1 === true && var2 === true) :
//do something
break;
case (var1 === false && var2 === false) :
//do something
break;
default:
}
This will always execute the switch, pretty much just like if/else but looks cleaner. Just continue checking your variables in the case expressions.
How about a bitwise operator? Instead of strings, you're dealing with "enums", which looks more "elegant."
// Declare slider's state "enum"
var SliderOne = {
A: 1,
B: 2,
C: 4,
D: 8,
E: 16
};
var SliderTwo = {
A: 32,
B: 64,
C: 128,
D: 256,
E: 512
};
// Set state
var s1 = SliderOne.A,
s2 = SliderTwo.B;
// Switch state
switch (s1 | s2) {
case SliderOne.A | SliderTwo.A :
case SliderOne.A | SliderTwo.C :
// Logic when State #1 is A, and State #2 is either A or C
break;
case SliderOne.B | SliderTwo.C :
// Logic when State #1 is B, and State #2 is C
break;
case SliderOne.E | SliderTwo.E :
default:
// Logic when State #1 is E, and State #2 is E or
// none of above match
break;
}
I however agree with others, 25 cases in a switch-case logic is not too pretty, and if-else might, in some cases, "look" better. Anyway.
var var1 = "something";
var var2 = "something_else";
switch(var1 + "|" + var2) {
case "something|something_else":
...
break;
case "something|...":
break;
case "...|...":
break;
}
If you have 5 possibilities for each one you will get 25 cases.
First, JavaScript's switch is no faster than if/else (and sometimes much slower).
Second, the only way to use switch with multiple variables is to combine them into one primitive (string, number, etc) value:
var stateA = "foo";
var stateB = "bar";
switch (stateA + "-" + stateB) {
case "foo-bar": ...
...
}
But, personally, I would rather see a set of if/else statements.
Edit: When all the values are integers, it appears that switch can out-perform if/else in Chrome. See the comments.
I don't believe a switch/case is any faster than a series of if/elseif's. They do the same thing, but if/elseif's you can check multiple variables. You cannot use a switch/case on more than one value.
If the action of each combination is static, you could build a two-dimensional array:
var data = [
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
[21,22,23,24,25]
];
The numbers in above example can be anything, such as string, array, etc. Fetching the value is now a one-liner (assuming sliders have a value range of [0,5):
var info = data[firstSliderValue][secondSliderValue];
You could give each position on each slider a different binary value from 1 to 1000000000
and then work with the sum.
Yeah, But not in a normal way. You will have to use switch as closure.
ex:-
function test(input1, input2) {
switch (true) {
case input1 > input2:
console.log(input1 + " is larger than " + input2);
break;
case input1 < input2:
console.log(input2 + " is larger than " + input1);
default:
console.log(input1 + " is equal to " + input2);
}
}
I did it like this:
switch (valueA && valueB) {
case true && false:
console.log(‘valueA is true, valueB is false’)
break;
case ( true || false ) && true:
console.log(‘valueA is either true or false and valueB is true’)
break;
default:
void 0;
}
Related
I'm creating a little game in HTML/JS/CSS for an exercise, and I've created a board game of 100 squares with <tr></tr and <td></td>.
There are two players on my board and, on each round, I check the squares around the two players, to see if there is a weapon or a player on this square.
But to check if there is a player on the square, I need to check if the square exist first. That' why I use a lot of switch case statements:
switch (true) {
case (squareAround != undefined): //I check if a square around is not undefined
switch (true) { //if the square exists, let's check if there is a player on it
case (playerOnIt === true):
//start the fight if there is a player on it
}
}
This is of course a simplified version. The break and default statements are not here.
The problem is, sometimes the square is "undefined" and the program doesn't go further, just as I want. But some other times, the square is detected as "undefined" but the program continues anyways. The case is clearly "false" but the switch case isn't working.
I used the console, and this exemple where it doesn't work : in the two first cases the square exist, and then it shows me the two HTML element.
But in the third cases, it's false, but the switch case works anyway, goes further, and gives me the HTML element... which is "undefined" !
What can possibly go wrong ?
Thanks for the help
Edit : here is some original code, ton answer the question of someone. But I don't know if it can help :
switch (true) {
case ($('td')[numberCasePlayer + i + l] != undefined):
switch (true) {
case ($('td')[numberCasePlayer + i + l].getAttribute('playeronit') === playeronitCheck):
fight()
break
}
case ($('td')[numberCasePlayer + i + m] != undefined):
switch (true) {
case ($('td')[numberCasePlayer + i + m].getAttribute('playeronit') === playeronitCheck):
fight()
break
}
case ($('td')[numberCasePlayer + i + n] != undefined):
switch (true) {
case ($('td')[numberCasePlayer + i + n].getAttribute('playeronit') === playeronitCheck):
fight()
break
}
case ($('td')[numberCasePlayer + i].getAttribute('weapon') === 'true'):
$('#' + $('td')[numberCasePlayer + i].getAttribute('weapontype')).css('display', 'none')
}
break
The right format for the switch statement is like:
switch(someVariable) {
case value1: doSomething; break;
case value2: doSomething; break;
case value3: doSomething; break;
...
default: doSomething;
}
It's straight forward if you do it with just if statements.
if(squareAround) {
if(playerOnIt) {
//start the fight if there is a player on it
}
}
I am currently working on project, where are parts of code that I don't understand. One of them you can see below (written in JS):
switch (true) {
case parseInt(data):
return 'data';
case parseInt(row):
return 'row';
default:
return 'default';
}
I created JSFiddle to test this switch(true) statement and to see how it behaves. It always returns 'default' string. Can someone explain to me what is happening there, please?
JSFiddle switch test
A switch in JavaScript simply compares if the value of the case is strictly equal (===) to what’s inside the switch (in this case true). This is usually used to compare strings, but booleans would also work, although it is less common. Take the following example:
switch (true) {
case 1 + 1 === 3:
return 'A';
case 2 * 2 === 4:
return 'B';
default:
return 'C';
}
This code would return 'B' as it is the first case to match true. If none of the cases would match true, it would return 'C'.
Regarding your specific scenario; I would recommend rewriting your code to the following:
if (parseInt(data) === true) {
return 'data';
}
if (parseInt(row) === true) {
return 'row';
}
return 'default';
This code does the exact same thing as yours, but it is immediately clear to the reader what is happening.
I am not sure what your goal is with this function, so I cannot recommend the best way to solve your problem. Although, I can explain to you why it might not be working.
The parseInt function will always return a number or NaN (in case the input cannot be parsed). Although a number can be truthy, it will never be strictly true. That's why your function always returns 'default'. Again, I don't know what your goal is, but you might want to check if the value is truthy instead of true:
if (parseInt(data)) {
// Data can be parsed to a number and is not 0
return 'data';
}
if (parseInt(row)) {
// Row can be parsed to a number and is not 0
return 'row';
}
return 'default';
It'll execute the first case that evaluates to true. If no case is true, it'll execute the default block
For example:
switch (true) {
case 1 === 1:
console.log('ok1');
break;
case 2 === 2:
console.log('ok2');
break;
default:
console.log('not ok');
}
will console.log('ok1')
How can I achieve that users can add multiply custom if-statements?
For example let's say there is a given variable called x with a given value of let's say 8.
The user sees that x = 8 and has a button to add an if-statement. He clicks the button and can insert the condition which triggers an event (let's say it prints "Hello World"). So he enters "x < 100" into the field which is true. Therefore "Hello World" is printed.
After clicking the button once again, he is able to add an other condition, let's say "x < 7" which is also true. Because both conditions are true, "Hello World" is still printed.
I think you got the point of my questions, even though I lack the vocabulary.
So how could I manage to let user add an undefined amount of conditions which will be checked before "Hello World" is printed?
The only solution I know is to limit the possible amount of conditions and check each one if it is empty / what the conditions says.
Thanks a lot!
Unless you want to build an entire language you have to get clear on what exact operations you are going to allow here.
For example the operation of < and > and ==, basically all comparison operations (<= and >= as well) can be implemented via the following:
/* your X variable, might be var if you desire to change */
let x = 12
/* the array of conditions the user entered */
var conditions : [(((Int, Int) -> Bool), Int)] = []
/* some user input - read as e.g. "x > 2"*/
conditions.append((<, 100))
conditions.append((>, 2))
conditions.append((==, 12))
/* you evaluate all conditions in the following way */
let eval = conditions.map { $0(x, $1) }
let allTrue = !eval.contains(false)
/* allTrue would be true in this case because 12 < 100 && 12 > 2 && 12 == 12 */
Your "hard" job is it now to interpret the user input as some condition. But that is not too difficult, you simply need a mapping of the text input of "<" to the actual operator <.
You can adjust the above code to take care of Double instead of Int easily if you fell like you need that. But you have to aware of floating point inaccuracy and the problem that arise when checking for equality (thanks to #dfri for pointing this out).
A little bit more difficult part comes in regards to combining the conditions with or instead of and what above code does and what you currently describe in your question.
Just because I like closures: The following is the entire input reading and parsing:
func getOperator(str: String) -> ((Int, Int) -> Bool)? {
switch str {
case "<":
return (<)
case ">":
return (>)
case "==":
return (==)
case "<=":
return (<=)
case ">=":
return (>=)
default:
return nil
}
}
func parseUserInput(str:String) -> (((Int, Int) -> Bool), Int) {
var input = str as NSString
input = input.stringByReplacingOccurrencesOfString(" ", withString: "")
//let variable = input.substringToIndex(1) // in case you want more than one variable, but that will have to change the entire setup a bit
// this has to be this "ugly" to incorporate both 1 char and 2 char long operators
let operato = input.substringFromIndex(1).stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet())
let number = input.substringFromIndex(operato.lengthOfBytesUsingEncoding(NSASCIIStringEncoding) + 1)
if let number = Int(number), op = getOperator(operato) {
return (op, number)
}
return ((<, 999999)) // need some error handling here
}
conditions.append(parseUserInput("x > 123"))
Instead of resolving the operator using a function you can even use a plain old dictionary mapping from ">" to (>) etc.
First you need a way to switch between operators. A very simple enum is perfect for this. Just add all the operators you want to use.
enum Operator : String {
case biggerThan = ">"
case smallerThan = "<"
case equal = "=="
init?(string:String) {
switch string {
case ">" :
self = .biggerThan
case "<" :
self = .smallerThan
case "==" :
self = .equal
default :
return nil
}
}
}
Each time a user clicks a button and inserts a condition, a corresponding Condition value will be created.
struct Condition {
var value: Int
var operation: Operator
}
This function returns a Bool depending on x, the inputValue and the chosen operator.
func checkCondition(x: Int, condition: Condition) -> Bool {
switch condition.operation {
case .biggerThan :
return condition.value > x
case .smallerThan :
return condition.value < x
case .equal :
return condition.value == x
}
}
This does the same but for a whole bunch of conditions. Here you can implement more logic. If all need to be true for example add : if !result { return false }.
func checkAllConditions(x:Int, conditions: [Condition]) {
for condition in conditions {
let result = checkCondition(x, condition: condition)
print(result)
}
}
Now all you need to do is store conditions in an array as the user creates them
func userCondition(operation:String, input:String) -> Condition? {
guard let op = Operator(string: operation) else {
return nil
}
guard let doubleValue = Double(input) else {
return nil
}
return Condition(value: Int(doubleValue), operation: op)
}
let conditionA = userCondition("<", input: "10")! // use if let instead of !
let conditionB = userCondition(">", input: "10")! // use if let instead of !
let conditionC = userCondition("==", input: "23")! // use if let instead of !
var x : Int = 23
checkAllConditions(x, conditions: [conditionA,conditionB,conditionC])
struct MyConditions {
let myEps: Double = 0.001
var x: Double
var lessThan = [Double]()
var equalTo = [Double]()
var greaterThan = [Double]()
init(x: Double) {
self.x = x
}
mutating func addConstraint(operand: Double, op: String) {
if op == "<" {
lessThan.append(operand)
}
else if op == "==" {
equalTo.append(operand)
}
else if op == ">" {
greaterThan.append(operand)
}
}
func checkConstraints() -> Bool {
for op in lessThan {
if !(x < op) {
return false
}
}
for op in equalTo {
if !(x - myEps < op && x + myEps > op) {
return false
}
}
for op in greaterThan {
if !(x > op) {
return false
}
}
return true
}
}
Tests:
func feasibleHelloWorld(x: MyConditions) {
if x.checkConstraints() {
print("Hello world!")
}
}
var x = MyConditions(x: 8)
x.addConstraint(100, op: "<")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!
x.addConstraint(8, op: "==")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!
x.addConstraint(7, op: "<")
x.checkConstraints() // false
feasibleHelloWorld(x) // ... nothing
I have an "enum" declared like so:
var PlaceType = {
PASSABLE_TERRAIN: 1,
IMPASSABLE_TERRAIN: 0,
SOMEWHAT_PASSABLE_TERRAIN: 2,
PATH: 3
};
and a function declared like this:
setPlaceType(placeType) {
this.clear = false;
this.placeType = placeType;
alert("before switch "+(PlaceType.SOMEWHAT_PASSABLE_TERRAIN==this.placeType));
switch(this.placeType) {
case PlaceType.PASSABLE_TERRAIN: {
alert("Case PASSABLE");
break;
}
case PlaceType.IMPASSABLE_TERRAIN: {
alert("Case IMPASSABLE");
break;
}
case PlaceType.SOMEWHAT_PASSABLE_TERRAIN: {
alert("Case SOMEWHAT_PASSABLE");
break;
}
case PlaceType.PATH: {
alert("Case PATH");
break;
}
default: {
alert("case default");
}
}
}
if I call it like this:
setPlaceType(1);
I get the following alerts: "before switch true", "case default"
if I call it like this:
setPlaceType(2);
I get the following alerts: "before switch false", "case default"
In other words, the function is called with the proper argument, which, when doing (what it seems to me to be) the same comparison as the switch but via "==" I get correct behavior, but the switch never matches the values to the appropriate case. Does anybody know why?
The comparison operator will cast both operands to strings if either operator is a string. If you pass in a string, you are comparing string == number which will cast the number to a string and, in the case of passing the string '2', it will be true.
switch case comparison uses the identity operator === and will fail if the operands are not the same type.
long story short, make sure you are always passing a number if your cases are comparing against numbers, you can double check like this:
setPlaceType(placeType) {
if (typeof placeType !== 'number') {
throw new Error('You must pass a number to setPlaceType!');
}
...
}
also, you should be calling your function like this:
setPlaceType(PlaceType.PASSABLE_TERRAIN);
otherwise there's not really any point to using the "enumeration" (i use that term loosely) object.
Refering to this => Switch-Case for strings in Javascript not working as expected
Switch do a ===, while if do a ==.
Hope this help! have a nice day
When you are doing the comparison using == js is using type-coercion to cast the 2 operands to an intermediate type, string in this case, and thus compare them successfully.
So to get the effect to work with your switch statement, you will need to cast as such
this.placeType = parseint(placeType);
What you also got to learn here is that it is not really an ideal practice to compare 2 values in javascript using the == operator, instead use the === operator which also checks for the types to be the same. So in your case,
alert("before switch "+(PlaceType.SOMEWHAT_PASSABLE_TERRAIN==this.placeType));
would have failed if you would have used === as you are comparing an int and string
Working demo here: http://jsfiddle.net/pratik136/ATx8c/
The matching case is determined using the === identity operator, not the == equality operator. The expressions must match without any type conversion. It would fail if you are passing in a string and not an integer.
setPlaceType(1); //"Case PASSABLE"
setPlaceType("1"); //"case default"
Example running your code with the above lines: jsFiddle
So if you are saying it is failing, you are probably comparing a string to a number. Use parseInt.
this.placeType = parseint(placeType,10);
Another way to use enum for switch case:
const PlaceType = Object.freeze({
PASSABLE_TERRAIN: 1,
IMPASSABLE_TERRAIN: 0,
SOMEWHAT_PASSABLE_TERRAIN: 2,
PATH: 3
});
function setPlaceType(placeType){
return({
0:"Case IMPASSABLE_TERRAIN",
1:"Case PASSABLE_TERRAIN",
2:"Case SOMEWHAT_PASSABLE_TERRAIN",
3:"PATH"
}[placeType]);
}
Ok so I'm trying to write some code to determine whether or not values in a static array are positive, negative or equal to zero.
So the array is populated and I'd use a switch statement to go through the values and output text depending on if it is above, below or equal to zero.
Here's some of the code I've been doing so far with this.
Please keep answers which pertain to the use of switches! Thanks in advance.
Note: I'm teaching myself JS, so I'm new to this. Here's my code so far:
// JavaScript Document
var numbers=new Array();
numbers[0]="1";
numbers[1]="2";
numbers[2]="3";
numbers[3]="-1";
numbers[4]="-2";
numbers[5]="-3";
numbers[6]="0";
switch (numbers) {
case "positive":
if (numbers>0)
{alert("DERP")};
break;
case "negative":
if (numbers<0)
{alert("NO DERP")};
break;
case "zero":
if (numbers==0)
{alert("STILL DERP")};
break;
}
You need to loop through the array, and check each element. A switch is not the right tool here, it will not do what you want. switches may be a way of doing if/else, but they only check for equality, not less than/greater than.
var str = 'a'
switch(str){
case 'a':
alert(1);
break;
case 'b':
alert(2);
break;
default:
alert(0);
break;
}
This alerts 1.
If the value of str matches one of the case statements (you can't use < or > in the case), the code will run. Otherwise defualt will run. They are not "labels", so checking the value inside the cases makes no sense.
You need to loop, then just use an if/else.
for(var i=0, len=numbers.length; i<len; i++){
var num = numbers[i];
if(num > 0) alert('DERP');
else if(num < 0) alert("NO DERP");
else alert("STILL DERP");
}
You compare string and numbers.
The numbers in your array are surrounded by "" : this make string. You should remove these "" in your array or add "" in your switch.