JavaScript switch case using enum - javascript

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]);
}

Related

Javascript: Convert string to computable

please someone help me about my javascript code. I want to convert string to be computable.
Example:
var string = "34.5 + 30";
the javascript function or code will automatically compute my string value. So the result will be 64.5 with a float or decimal data type.
hope someone can answer my query.
Use eval function.
Reference
The eval() function evaluates JavaScript code represented as a string.
But there is a security issue in this.
Executing JavaScript from a string is an enormous security risk. It is
far too easy for a bad actor to run arbitrary code when you use
eval(). See Never use eval()!, below.
var myString = "34.5 + 30";
console.log(eval(myString));
Since eval has some security issues, its always adviced not to use it. You could either make use of some custom libraries or implement your own parsing logic.
Please find a small paring logic from my side.
Please note, this evaluates the mathematical expressions linearly. This doesnot works with BODMAS rule or will not evaluate any complex expression. This is to evaluate a mathematical expression that contains only numbers, and basic operators such as +, -, * and /. If you wish to have custom validations you could build on top of this or can implement a solution of your own.
I have added the description as code comment
const myString = "34.5 + 30";
// Regex to split the expression on +, -, *, / and spaces
const isNumeric = /(?=[-+*\/(\s+)])/;
// Valid operators
const operators = ['+', '-', '*', '/'];
// Split the string into array
const expressionArray = myString.split(isNumeric);
// Object to hold the result and the operator while parsing the array generated
const result = { result: 0, operator: '' };
// loop though each node in the array
// If an operator is found, set it to result.operator
// If not an operator, it will be a number
// Check an operator is already existing in result.operator
// If then perform the operation with the current node and result and clear the result.operator
expressionArray.forEach((node) => {
const trimmedNode = node.trim();
if (trimmedNode) {
if (operators.indexOf(trimmedNode) === -1) {
if (result.operator) {
switch (result.operator) {
case '+':
result.result += Number(node);
break;
case '-':
result.result -= Number(node);
break;
case '*':
result.result *= Number(node);
break;
case '/':
result.result /= Number(node);
break;
result.operator = '';
}
} else {
result.result += Number(node);
}
} else {
result.operator = trimmedNode;
}
}
});
console.log(result.result);

How does that switch case work in JS? What does mean switch(true)?

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')

why mod (%) calculation result of zero will not consider as falsy in javascript condition evaluation

if (!5%5) {
console.log('its a 5%!');
}
if (5%5 === 0) {
console.log('its a 5%! but eval differently');
}
https://codepen.io/adamchenwei/pen/ZXNraK?editors=0010
Something like above you will only see 2nd statement to evaluate to be true. Why is that? Isn't first statement ! help revert the value into true already. What did I missed?
!5 is 0.
0 % 5 is falsy.
Therefore, your if doesn't trigger.
The expression !5%5 is interpreted as if it were parenthesized (!5)%5. In other words, the ! operator binds very tightly, so !5 is evaluated before the % operator.
Consider an expression like -x+y. Clearly, that means (-x)+y, and not -(x+y), because of traditional arithmetic operator precedence rules. The ! operator is in that respect similar to unary -.
The expression !5 is 0, and 0%5 is 0, so !5%5 is not "truthy".
It's because the result of 5%5 is not a number (NaN), and you can't invert it. But if you will store this result into variable, or will wrap 5%5 into parentheses (which will change the order of execution) you can use it as you tried. Here are some rows, which should help you with understanding the behavior:
var result = 5%5;
if (!result) {
console.log('Works with variable');
}
if (!5%5) {
console.log('Works without variable');
} else {
console.log('!5%5 evaluates to "!NaN"');
}
if (!(5%5)) {
console.log('!(5%5) works with parentheses');
} else {
console.log('!(5%5) doesn\'t work');
}
console.log("The type of 5%5 is: ", typeof 5%5);
console.log("The type of (5%5) is: ", typeof (5%5));
console.log("The type of 5%5 stored in variable is: ", typeof result);
console.log("The type of !(5%5) is: ", typeof !(5%5));

unexpected results in evaluation of chains logical expressions javascript

I am writing a program to identify special numbers according to the criteria laid out in this code wars kata:
http://www.codewars.com/kata/catching-car-mileage-numbers
Here is a link to my full code and tests:
http://www.codeshare.io/UeXhW
I have unit tested my functions which test for each of the special number conditions and they appear to be working as expected. However, I have a function:
function allTests(number, awesomePhrases){
var num = number.toString().split('');
// if any criteria is met and the number is >99 return true
return number > 99 && (allZeros(num) || sameDigits(num) || incrementing(num) || decrementing(num) || palindrome(number) || matchPhrase(number, awesomePhrases)) ? true : false;
}
which determines if any of the criteria of being a special number is met and that's not working as expected. For example, when I tested the allZeros() function on 7000 it returned true, but alltests(7000) is returning false. Is there something about how chains of logical expressions are evaluated that I don't understand or is the problem something else?
I have looked at W3schools and MDN to try and diagnose the problem.
Change all your !== to != will do.
False results as long as allTests() executes with a second argument even it it's the empty string, as follows:
allTests(7000,"");
If the function is called with just one argument, i.e. the number, expect this error:
Uncaught TypeError: Cannot read property 'length' of undefined
The error message refers to one of the functions in the logic chain, namely matchPhrase() which expects two parameters: number and awesomePhrases. If instead of providing an empty string, you use null, you'll also get the same error message.
JavaScript doesn't support the concept of default parameters -- at least not in a way that one might expect; the parameters default to undefined. But there is a way to work around this hurdle and improve the code so that one may avoid this needless error. Just change matchPhrase() as follows:
function matchPhrase(number, awesomePhrases){
awesomePhrases = typeof awesomePhrases !== 'undefined' ? awesomePhrases : "";
for(var i = 0, max=awesomePhrases.length; i < max; i++){
if(number == awesomePhrases[i]){
return true;
}
}
return false;
}
The first statement accepts the second argument's value as long as it is not the undefined value; if so, then the variable gets set to the empty string. (Source for technique: here).
To make the code more readily comprehensible, I suggest rewriting allTests() as follows, so that the code follows a more explicit self-documenting style:
function allTests(number, awesomePhrases){
var arrDigits = number.toString().split('');
// if any criteria is met and the number is >99 return true
return number > 99 && (allZeros( arrDigits ) || sameDigits( arrDigits ) || incrementing( arrDigits ) || decrementing( arrDigits) || palindrome(number) || matchPhrase(number, awesomePhrases)) ? true : false;
}
This function takes a number and uses its toString() method to convert the number to a string. The resulting string which is not visible will split itself on the empty string so that the result of arrDigits is an array of numerical strings, each one consisting of just one digit. This is the point of origin for the ensuing problem with allZeros() which compares a stringified digit with a number.
Incidentally, in the function allTests() there is an awfully lengthy ternary expression. The syntax is fine, but you might wish to rewrite the code as follows:
function getCriteriaStatus(arrDigits,number,awesomePhrases) {
var criteria = new Array();
criteria[0] = allZeros( arrDigits );
criteria[1] = sameDigits( arrDigits );
criteria[2] = incrementing( arrDigits );
criteria[3] = decrementing( arrDigits);
criteria[4] = palindrome(number);
criteria[5] = matchPhrase(number, awesomePhrases);
var retval = false;
for (var i=0, max=6; i < max; i++) {
if ( criteria[i] == true ) {
retval = true;
break;
}
}
return retval;
}
function allTests(number, awesomePhrases){
var arrDigits = number.toString().split('');
var criteria_met = getCriteriaStatus(arrDigits,number,awesomePhrases);
return (number > 99 && criteria_met);
}
To obtain the desired true result from allTests() when it invokes allZeros(), rather than complicate the code by using parseInt(), I suggest rewriting allZeros() and any other functions containing code that compares a numerical string value with a number by changing from the identity operator to the equality operator. The change involves merely replacing === with == as well as replacing !== with !=. The code that compares values of the same data type, using the identity operators, those operators may, and probably should, remain unchanged. (See here).

Can I use a case/switch statement with two variables?

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;
}

Categories

Resources