Switch Case Regex Test - javascript

var path = location.pathname;
switch(path){
case (/\/memberlist/).test(path) :getCSS('url-22.css'); break;
case (/\/register/).test(path): getCSS('url-6.css'); break;
case (/buy-credits/g).test(path): getCSS('url-7.css'); break;
case (/\/?u(\d+)friends$/).test(path): getCSS('url-8.css'); break;
case (/\/privmsg/).test(path): getCSS('url-9.css'); break;
case (/\/?u(\d+)wall$/).test(path): getCSS('url-4.css'); break;
}
function getCSS(url,media){
var a = document.createElement('link');
a.href=url;
a.media= media || 'screen';
a.rel="stylesheet";
return (document.getElementsByTagName('head')[0].appendChild(a));
}
That is my code, and for some reason it's not running the function that should run. For testing purpose we could change var path="/memberlist" and it still won't run. Can someone explain to me why this won't run. Don't really use switch statements

change
switch(path){
to
switch(true){
as you can see in thread I'm reffering to in comment.

None of the answers posted show a correct method to use a RegExp pattern in a switch case so I thought I'd post:
switch (myVar) {
case 'case1':
/...do work
break
case /[a-z]*/.test(myVar) && myVar:
/...regex match, do work
break
}

switch-case doesn't work that way.
regex.test() method returns a boolean (true/false) and you are comparing that against the input string itself which will not be true for any of the case statement.
You need to convert switch-case into multiple if / else if / else block to execute your logic.

Just for the record, the switch case could be rewritten to:
getCSS(
/\/memberlist/).test(path) && 'url-22.css' ||
/\/register/).test(path) && 'url-6.css' ||
/buy-credits/g).test(path) && 'url-7.css' ||
/\/?u(\d+)friends$/) && 'url-8.css' ||
/\/privmsg/).test(path) && 'url-9.css' ||
/\/?u(\d+)wall$/).test(path) && 'url-4.css' ||
'default'
);
Or rewrite getCSS, using a helper object
var path2url = {
css: [
{re: /\/register/, css: 'url-22.css'},
{re: /buy-credits/g, css: 'url-6.css'},
{re: /\/?u(\d+)friends$/, css: 'url-8.css'},
{re: /\/privmsg/, css: 'url-8.css'},
{re: /\/?u(\d+)wall$/, css: 'url-4.css'}
],
getURL: function(path) {
var i = this.css.length;
while (--i) {
if (this.css[i].re.test(path)) {
return this.css[i].css;
}
}
return null; // or something default
}
};
function getCSS(path,media){
var a = document.createElement('link');
a.href= path2url.getURL(path); // <=
a.media= media || 'screen';
a.rel="stylesheet";
return (document.getElementsByTagName('head')[0].appendChild(a));
}

Have a look
switch(str){
case (/(abc|xyz)/.test(str) ? str : false):
// Do some stuff
break;
default:
// Do default stuff
}

Related

Switch statement only returns the default case

Can someone help me understand, why is my switch case returning the default value. Even when I change all values it only returns the default at first I thought it was a hoisting issue in my code but after debugging it's I found it's the statement, it ignores all other cases. (p.s please don't be mean I just want to understand, the other examples I've seen aren't simply explained and don't have much up votes so I did try.)
var shippingMethod = document.querySelector("[name=r_method]:checked").value;
var shippingChoice;
switch(shippingMethod) {
case "usps":
shippingChoice = 2;
break;
case "ups":
shippingChoice = 3;
break;
default:
shippingChoice = 0;
break;
}
console.log(shippingChoice);
I would suggest adding an if statement to verify there is a value for shippingMethod. As well, when querying for the value, make sure to include quote ("") around the value of the name.
var shippingMethod = "default";
var shippingChoice;
if (document.querySelector('[name="r_method"]:checked') != null)
{
shippingMethod = document.querySelector('[name="r_method"]:checked').value;
}
switch(shippingMethod) {
case "usps":
shippingChoice = 2;
break;
case "ups":
shippingChoice = 3;
break;
default:
shippingChoice = 0;
break;
}
console.log(shippingChoice);

Is there a better way to write this switch in JavaScript?

I have a switch with the following conditions:
The first case is or between three names (ROKA, MOKA and TOKA).
The second case is another name (KOKA) but with two additional conditions to display an alert.
Lastly, I have some other conditions to check inside the default block, as I'm unable to use a case for them.
This is my code:
var myname= 'JOKA';
var dhaba = false;
switch (myname) {
case ('ROKA'):
case ('MOKA'):
case ('TOKA'):
alert('EEE');
break;
case ('KOKA'):
// This will work as Goto to final default:
if (condition1 && condition2) {
alert('FEEE');
break;
}
default:
if (dhaba && myname != 'ROKA' && myname != 'TOKA') {
alert('TEEEE');
} else {
alert('CHEEE');
}
}
Is there a better way to write this code?
When you reach default, then myname is always unequal to the previously checked values. It is sufficient to use
default:
if (dhaba) {
alert('TEEEE');
} else {
alert('CHEEE');
}
I think switch is not the best option for your use case.
Also, as #NinaScholz has pointed out, the myname != 'ROKA' && myname != 'TOKA' will always be true, as otherwise you will fall in the first case.
Let's go step by step and see different ways to refactor your code:
πŸ‘Œ Simplified (Non-Switch) Code
The easies and most straightforward way to write your code is like this:
const myname = 'JOKA';
const dhaba = false;
if ('ROKA' === myname || 'MOKA' === myname || 'TOKA' === myname) {
alert('EEE');
} else if (myname === 'KOKA' && true && true) {
alert('FEEE');
} else {
alert(dhaba ? 'TEEEE' : 'CHEEE');
}
Note how the redundant checks have been removed and the last if - else block have been replaced with a ternary operator.
It is possible that your code is not exactly like the example you provided or that it changes overtime. In that case, you may consider other options other than the above simplified code.
πŸ‘‰ Checking multiple matches from a single variable using Array.prototype.indexOf()
However, you may have a lot more elements to check in the first if. In that case you could use an Array and Array.prototype.indexOf() to check if there's any match inside it (it will return -1 if there isn't any):
const myname = 'JOKA';
const dhaba = false;
if (['ROKA', 'MOKA', 'TOKA'].indexOf(myname) !== -1) {
alert('EEE');
} else if (myname === 'KOKA' && true && true) {
alert('FEEE');
} else {
alert(dhaba ? 'TEEEE' : 'CHEEE');
}
πŸ‘‰ N Input - Output (String) Pairs + Complex Default with Switch
It is also possible that you have multiple myname values that map to multiple alert() params, so you may feel tempted to write something like this:
const myname = 'JOKA';
const dhaba = false;
switch(myname) {
case 'XXX-1': alert('YYY-1'); break;
case 'XXX-2': alert('YYY-2'); break;
...
case 'XXX-N': alert('YYY-N'); break;
default:
if (myname === 'KOKA' && true && true) {
alert('FEEE');
} else {
alert(dhaba ? 'TEEEE' : 'CHEEE');
}
}
While this is fine and, actually, I think it is cleaner and less error-prone than checking an additional condition inside a case block, as you did in your example, and based on that do something and break or let the next block execute, I would advise you to consider using object literal lookups instead.
πŸ‘‰ N Input - Output (String) Pairs + Complex Default with Object Literals Lookups πŸ”Ž
There are multiple advantages to use them: better readability, easier debugging, maintainability, concision (no need to add break, for example)... I think the most important one for you, as you added the tag performance in your question, is that it is more performant.
This is because while the switch has to evaluate each case condition until it fins a break, so their order matters, the object lookup is just a hash table lookup, that is, O(1).
With this in mind, we could refactor the last example like this:
const myname = 'JOKA';
const dhaba = false;
const output = {
'XXX-1': 'YYY-1',
'XXX-2': 'YYY-2',
...
'XXX-N': 'YYY-N',
}[myname];
// Note output will be undefined if there isn't a match, so the first if
// will be evaluated to false in that scenario:
if (output) {
alert(output);
} else if (myname === 'KOKA' && true && true) {
alert('FEEE');
} else {
alert(dhaba ? 'TEEEE' : 'CHEEE');
}
πŸ‘‰ N Input - Output (String) Pairs + Single-Value Default with Object Literals Lookups πŸ”Ž and || (or)Β Operator
Also, note that if your default were just using another value inside the if, you could do that with a simple || operator:
const myname = 'JOKA';
const output = {
'XXX-1': 'YYY-1',
'XXX-2': 'YYY-2',
...
'XXX-N': 'YYY-N',
}[myname] || 'DEFAULT OUTPUT';
alert(output);
πŸ‘‰ N Input - Output (Arbitrary Code) Pairs with Object Literals Lookups πŸ”Ž
Note you could also execute arbitrary code for each case in your objects using functions or arrow functions:
const myname = 'JOKA';
const output = {
'XXX-1': () => { /* Do something... */ },
'XXX-2': () => { /* Do something... */ },
...
'XXX-N': () => { /* Do something... */ },
}[myname]();
...
Note that you could declare those functions above the object declaration and share them across multiple keys that should have the same behaviour:
const myname = 'JOKA';
const f1 = () => { /* Do something 1... */ };
const output = {
'XXX-1': f1,
'XXX-2': f1,
...
'XXX-N': () => { /* Do something... */ },
}[myname]();
...
For more on replace switchs with object literal lookups, take a look at this post: https://toddmotto.com/deprecating-the-switch-statement-for-object-literals

Switch is not properly working in javascript

I have a switch statement which has several cases. These cases compare values and assign a text to a variable. But when I try to execute this switch, it always executes the default case. But my condition is true.. Why?
Here is my value
Apartment
Here is my code
var rental_cat = $('#rentals_type').val();
alert(rental_cat);
var rental_type = "";
switch (rental_cat) {
case (rental_cat == "Apartment"):
rental_type='daily';
alert(rental_type);
break;
case (rental_cat == "Office"):
rental_type='work_daily';
alert(rental_type);
break;
default:
rental_type='other';
alert(rental_type);
break;
}
When I execute this switch, it always gives me "other"
Remove the conditional expression inside the "case" clause.
Try this:
var rental_cat = $('#rentals_type').val();
alert(rental_cat);
var rental_type = "";
switch (rental_cat) {
case "Apartment":
rental_type='daily';
alert(rental_type);
break;
case "Office":
rental_type='work_daily';
alert(rental_type);
break;
default:
rental_type='other';
alert(rental_type);
break;
}
switch (rental_cat) {
case (rental_cat == "Apartment"):
is equivalent to
switch (rental_cat) {
case true:
which in turn is equivalent to
if (rental_cat === true)
You don't put a condition in the case, the condition is created as an equality check between the switch and the cases, so it should be like this instead:
switch (rental_cat) {
case "Apartment":
a switch is not the right structure to deal with this problem. Here I'd recommend a map:
var rentalTypesByCat = {
DEFAULT: "other",
"Apartement": "daily",
"Office": "work_daily",
}
var rental_cat = $('#rentals_type').val();
console.log("rental_cat:", rental_cat);
var rental_type = rentalTypesByCat[rental_cat] || rentalTypesByCat.DEFAULT;
console.log("rental_type:", rental_type);
or if you need it a bit more explicit (for example because some of your mapped values may be falsy themselves):
var rental_type = rentalTypesByCat[rental_cat in rentalTypesByCat? rental_cat: "DEFAULT"];
console.log("rental_type:", rental_type);

Javascript: change test() method name

Okay, I am making a text based game and I have been using the switch command like so
switch(true){
case /run/.test(g1):
prompt("run");
break;
}
the question I have is can I can I change the name of the test() method like so
switch(true){
case /run/.act(g1):
prompt("run");
break;
}
I thought if I created a function like so it would work
function act(str){
test(str);
return;
}
but it didn't... any help would be nice.
edit: fixed switch statements
So /run/ is a regex object. It has a method called test. It doesn't have a method act, so hence you can't call act() on it.
You'll need to use prototypes:
switch{
case /run/.act(g1):
prompt("run");
break;
}
RegExp.prototype.act = function (str) {
return this.test(str);
}
Here's an explanation of Prototypes.
If you really need to do this (please see What is the XY problem?) then you can add a prototype to the RegExp object.
var regex = /fo+/;
var str = 'fooooooooooooooo';
regex.test(str); //true
RegExp.prototype.act = function(str) {
if (str == 'fooooooo' && this.test(str)) {
return true;
} else {
return false;
}
}
regex.act(str); //false (str is not 'fooooooo')
Likewise, you can make an alias (but please, don't - it works fine as it is) by simply returning this.test():
RegExp.prototype.act = function(str) {
return this.test(str);
}

Can someone explain how JSON parsers work without using eval at all?

I can't comprehend how it works without using eval - what's the secret behind this?
Edit: Could someone present a trivial example of how the tree structure is converted to an object?
JSON has a well defined grammar which is used to construct a tree which is then converted to an object.
Get Douglas Crockford's book, Javascript: the Good Parts. Appendix E includes code implementing a JSON parser. It does not use eval.
I don't know specifics but it's not really hard. Just a smart combination of reading characters and substrings, interpreting what they mean and building up an array of data while you do it. Like any other parser.
There is no secret. How do you think eval() is implemented? It uses the same techniques that you would have to use if you had to parse JSON data, i.e. effectively reimplement part of eval().
Take a look at my parser for a good idea. It isn't perfect but the code is pretty easy to follow.
public static JsonStructure Parse(string jsonText)
{
var result = default(JsonStructure);
var structureStack = new Stack<JsonStructure>();
var keyStack = new Stack<string>();
var current = default(JsonStructure);
var currentState = ParserState.Begin;
var key = default(string);
var value = default(object);
foreach (var token in Lexer.Tokenize(jsonText))
{
switch (currentState)
{
case ParserState.Begin:
switch (token.Type)
{
case TokenType.BeginObject:
currentState = ParserState.Name;
current = result = new JsonObject();
break;
case TokenType.BeginArray:
currentState = ParserState.Value;
current = result = new JsonArray();
break;
default:
throw new JsonException(token, currentState);
}
break;
case ParserState.Name:
switch (token.Type)
{
case TokenType.String:
currentState = ParserState.NameSeparator;
key = (string)token.Value;
break;
default:
throw new JsonException(token, currentState);
}
break;
case ParserState.NameSeparator:
switch (token.Type)
{
case TokenType.NameSeparator:
currentState = ParserState.Value;
break;
default:
throw new JsonException(token, currentState);
}
break;
case ParserState.Value:
switch (token.Type)
{
case TokenType.Number:
case TokenType.String:
case TokenType.True:
case TokenType.False:
case TokenType.Null:
currentState = ParserState.ValueSeparator;
value = token.Value;
break;
case TokenType.BeginObject:
structureStack.Push(current);
keyStack.Push(key);
currentState = ParserState.Name;
current = new JsonObject();
break;
case TokenType.BeginArray:
structureStack.Push(current);
currentState = ParserState.Value;
current = new JsonArray();
break;
default:
throw new JsonException(token, currentState);
}
break;
case ParserState.ValueSeparator:
var jsonObject = (current as JsonObject);
var jsonArray = (current as JsonArray);
if (jsonObject != null)
{
jsonObject.Add(key, value);
currentState = ParserState.Name;
}
if (jsonArray != null)
{
jsonArray.Add(value);
currentState = ParserState.Value;
}
switch (token.Type)
{
case TokenType.EndObject:
case TokenType.EndArray:
currentState = ParserState.End;
break;
case TokenType.ValueSeparator:
break;
default:
throw new JsonException(token, currentState);
}
break;
case ParserState.End:
switch (token.Type)
{
case TokenType.EndObject:
case TokenType.EndArray:
case TokenType.ValueSeparator:
var previous = structureStack.Pop();
var previousJsonObject = (previous as JsonObject);
var previousJsonArray = (previous as JsonArray);
if (previousJsonObject != null)
{
previousJsonObject.Add(keyStack.Pop(), current);
currentState = ParserState.Name;
}
if (previousJsonArray != null)
{
previousJsonArray.Add(current);
currentState = ParserState.Value;
}
if (token.Type != TokenType.ValueSeparator)
{
currentState = ParserState.End;
}
current = previous;
break;
default:
throw new JsonException(token, currentState);
}
break;
default:
break;
}
}
return result;
}
trivial example of how to convert a string with json into an object without eval:
var txt='[\'one\',\'two\']';
var re1='(\\[)'; // Any Single Character 1
var re2='(\\\'.*?\\\')'; // Single Quote String 1
var re3='(,)'; // Any Single Character 2
var re4='(\\\'.*?\\\')'; // Single Quote String 2
var re5='(\\])'; // Any Single Character 3
var p = new RegExp(re1+re2+re3+re4+re5,["i"]);
var m = p.exec(txt);
if (m != null)
{
var c1=m[1];
var s1=m[2];
var c2=m[3];
var s2=m[4];
var c3=m[5];
return [s1, s2];
}
return null;
yes this a horrible way to do it, but it does what it claims for that string :p
JSON is a native representation of data. It is simply a creative implementation of JavaScript's built-in object format. Being native, it doesn't need to be "parsed" (in the sense that the programmer needs to worry about doing it) at all.

Categories