This question already has answers here:
Is it possible to use .contains() in a switch statement?
(2 answers)
Closed 2 years ago.
I've got this code
if (header.classList.contains("capricorn")) {
//star sign description
para.innerHTML = starSign.Capricorn;
} else if (header.classList.contains("aquarius")) {
para.innerHTML = starSign.Aquarius;
} else if (header.classList.contains("pisces")) {
para.innerHTML = starSign.Pisces;
I want to turn it in a switch statement, is that possible?
Consider parameterizing your checks instead, based on the properties of starSign object:
function chooseSign(classList, signs) {
return signs.find(s => classList.contains(s.toLowerCase());
}
... and using it accordingly:
const sign = chooseSign(header.classList, Object.keys(starSign));
if (sign) {
para.innerHTML = starSign[sign];
}
I assumed starSign is a collection of texts with only 12 keys. If that's not the case, consider making a separate array out of those.
In general, when you have a looooong series of if - else if - else if checks doing essentially the same stuff over and over, think about using separate function for the same purpose. Not only this gives you a chance to simplify the code (like in this example), but also isolates the business logic decision making your code both more readable and more testable.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I receive strings of code via simple POST requests, i am looking for a clever way (without having to run the script itself) to distinguish if it's a javascript script or css script, or at least to be quite sure (i'd say 55% possibility it is one of).
These are not files these are strings, so i don't have any information about the code in the string, no file, no file ext, no headers...
Do you have any advice/resource?
thanks a lot.
If this has to work with broken code too, I think your best chance is to search for "typical CSS" and "typical JS" stuff, and compare how much speaks for JS and how much for CSS.
Typical for JS are it's reserved words, and it's operators.
Typical for CSS is the structure: [, seperated selectors] { [ ; seperated key-value pairs] }
First a few utilities that triy to evaluate how much of a passed string is part of a particular language. (very basic approach, therefore should also work with broken code)
//returns **kind of** a percentage of how much of the string has been identified as JS/CSS
function evaluateCode(pattern, commentPattern, correctionalFactor){
correctionalFactor = +correctionalFactor || 1;
return function(string){
//removing comments and compacting whitespace.
//this avoids false hits, and provides a better estimation of how much significant text/code we have (to compute the percentage)
var t = string.replace(commentPattern || "", "").replace(/\s+/, " ");
return correctionalFactor * (t.match(pattern) || []).reduce(sumLengths, 0) / t.length;
}
}
var sumLengths = (acc, match) => acc + match.length;
var evaluateJS = evaluateCode(
/\b(?:function|return|arguments|this|var|const|let|typeof|instanceof|Array|Object)\b|[+\-*/<>&|=]+|[()\[\]\{\}]/g,
/\/\*[\s\S]*\*\/|\/\/[^\n]*/g,
1.5
);
var evaluateCSS = evaluateCode(
/[a-z0-9\.#:\[\]=,\s-]+\{(?:\s*[a-z-]+\s*:[^;]+;?)*\s*\}/gi,
/\/\*[\s\S]*\*\//g
);
And the usage:
var jsRatio = evaluateJS(string),
cssRatio = evaluateCSS(string);
//If there's less than 10% difference between the two estimations, I'd call it "unclear"
if(Math.abs(jsRatio - cssRatio) < .1){
console.log("result is ambigious, but I tend more towards");
}
console.log("%s (probabilities: css %f%, js %f%)", cssRatio > jsRatio? "css": "js", cssRatio, jsRatio);
I use an estimated/guessed "correctional factor" of 1.5 on evaluateJS, because the regex matches only a part of the code,
whereas the css-regex matches almost everything.
This factor only matters when the results are ambigious, usually there should be a huge gap between the two ratios.
Edit: another (probably better) regex to search for CSS:
/[a-z0-9\-]+\s*:[^;{}]+[;}]|(?:[#.]?[a-z]+(?:[#.:\s][a-z0-9-_]+)*\s*[,{])/gi
this is looking only for key-value pairs and "typical" selectors, containing ids and classes, rather than the whole structure, wich should be benefitial, if css-structure is broken or too complex for the fairly simple regex.
You might enclose the returned string in a block that prevents it from being executed (if it's JavaScript) and see if it can be parsed.
function isJavaScript(str)
{
try
{
Function('function(){' + str + '}');
return true; // Looks like valid JS
}
catch (error)
{
// no valid JavaScript, may be CSS
return false;
}
}
I don't think this is 100% foolproof, but it may work for your purpose.
This question already has answers here:
What does the comma operator do in JavaScript?
(5 answers)
Closed 9 years ago.
The last few days, I've been helping a friend learn Javascript. It's his first language in years and he remembers virtually nothing, so he's been starting pretty much entirely from scratch. He's been going through a simple tutorial and I've been providing him with some exercises to help him practice. The most recent exercise I gave him was the (apparently) classic FizzBuzz problem. He solved it with a bit of help, but he did something very interesting while working out his solution. He came up with the following code:
for (var x = 1; x <= 100; x++) {
if (x%3 == 0, x%5 != 0) {
console.log("Fizz");
}
else if (x%3 != 0, x%5 == 0) {
console.log("Buzz");
}
else if (x%3 == 0, x%5 == 0) {
console.log("FizzBuzz");
}
else {
console.log(x);
}
}
He wasn't familiar with boolean comparison operators, so he didn't use && and instead used commas. My expectation was that it would crash and say something about a syntax error, but to my surprise it ended up running fine and just printing out a bunch of "Fizz" and "Buzz" lines, with no "FizzBuzz" or numbers. Needless to say, I was confused, so I did a bit of experimentation. My first test was to run this:
if (true, true) console.log('true, true');
if (true, false) console.log('true, false');
if (false, true) console.log('false, true');
if (false, false) console.log('false, false');
Which gave me two lines of output:
'true, true'
'false, true'
From that, I made the guess that all comma did was cause it to evaluate nothing but the last expression in the list. I then tried running this code:
for (var i = 0; i < 16; i++) {
if ((Math.floor(i / 8) == 1), (Math.floor(i / 4) == 1), (Math.floor(i / 2) == 1), (i % 2 == 1)) {
console.log(i);
}
}
The output I got was all the odd numbers from 1-15, which confirmed my guess from my first test (since the last boolean in the comma-separated list was flipping every other iteration).
After all that long-winded context, my question is this: Is this comma syntax a known and intentional piece of the Javascript engine, or is it a strange, overlooked quirk of the interpreter? I know commas can be used for a few other things (initializing multiple variables in one line, declaring arrays, and separating parameters jump to mind), but I've never heard of them being used in conditional statements like this in any language, and I'm curious if anyone else knows whether or not this code should even run.
For reference, the FizzBuzz code and the second test I ran were both done using node, and the first test I ran was done in the Javascript console in Chrome, so it doesn't seem to be just a browser- or node-exclusive quirk if indeed it is one. Also, if you actually read this far, thank you.
The comma is an actual operator. It evaluates both of its operands (from left to right) and returns the value of the second operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
Its most common usage is to supply multiple parameters in a for loop, but it can also be used for other purposes.
I'm trying to develop a simplified poker game through Javascript. I've listed all possible card combinations a given player might have in its hand ordered by its value, like this:
switch(sortedHand)
{
//Pair
case [1,1,4,3,2]: sortedHand.push(1,"Pair"); break;
case [1,1,5,3,2]: sortedHand.push(2,"Pair"); break;
case [1,1,5,4,2]: sortedHand.push(3,"Pair"); break;
case [1,1,5,4,3]: sortedHand.push(4,"Pair"); break;
case [1,1,6,3,2]: sortedHand.push(5,"Pair"); break;
case [1,1,6,4,2]: sortedHand.push(6,"Pair"); break;
case [1,1,6,4,3]: sortedHand.push(7,"Pair"); break;
case [1,1,6,5,2]: sortedHand.push(8,"Pair"); break;
case [1,1,6,5,3]: sortedHand.push(9,"Pair"); break;
case [1,1,6,5,4]: sortedHand.push(10,"Pair"); break;
Even though the "sortedHand" array stores values succesfully (as I've seen through console.log), the switch() statement always returns the default case, and everyone gets an straight flush. I fear this is a matter of the literal approach I've used to declare possible array values to be compared with the whole of "sortedHand", but I don't know any better. Is it even possible to use switch() in such a manner?
You can try switching on a textual representation of the array.
switch(sortedHand.join(' '))
{
//Pair
case '1 1 4 3 2': sortedHand.push(1,"Pair"); break;
case '1 1 5 3 2': sortedHand.push(2,"Pair"); break;
case '1 1 5 4 2': sortedHand.push(3,"Pair"); break;
case '1 1 5 4 3': sortedHand.push(4,"Pair"); break;
// etc.
}
As an alternative to specifying every case directly, perhaps build a function dispatch table using an object and get rid of the switch entirely.
var dispatch = {};
// Build the table however you'd like, for your application
for (var i = 0; i < 10; i++) {
(function(i) {
var hand = ...; // Add your hand logic here
dispatch[hand] = function() { sortedHand.push(i, "Pair"); };
})(i);
}
// Execute your routine
dispatch[sortedHand.join(' ')]();
the switch() statement always returns the default case
That's because the comparison doesn't check the array contents, but the array object itself. Objects are considered equal by their identity, so nothing will be equal to an object instantiated by a literal.
Is it even possible to use switch() in such a manner?
Yes, one can use objects in switch statements, but you would have to use references in the cases. Not applicable to your problem.
In your case, I'd suggest a stringification:
switch(sortedHand.join())
{
//Pair
case "1,1,4,3,2": sortedHand.push(1,"Pair"); break;
case "1,1,5,3,2": sortedHand.push(2,"Pair"); break;
case "1,1,5,4,2": sortedHand.push(3,"Pair"); break;
case "1,1,5,4,3": sortedHand.push(4,"Pair"); break;
case "1,1,6,3,2": sortedHand.push(5,"Pair"); break;
case "1,1,6,4,2": sortedHand.push(6,"Pair"); break;
case "1,1,6,4,3": sortedHand.push(7,"Pair"); break;
case "1,1,6,5,2": sortedHand.push(8,"Pair"); break;
case "1,1,6,5,3": sortedHand.push(9,"Pair"); break;
case "1,1,6,5,4": sortedHand.push(10,"Pair"); break;
but I guess there's an even better, arithmetic solution to detect the patterns you're after. That would be shorter and faster, but I'm not sure what exactly this snippet is supposed to do.
a faster, potentially reusable, and more flexible way of doing it is to use an object instead of case:
var ok= {
'1 1 4 3 2':1,
'1 1 5 3 2':2,
'1 1 5 4 2':3,
'1 1 5 4 3':4
}[ sortedHand.join(' ') ] ;
if(ok){ sortedHand.push( ok ,"Pair"); }
objects work great when one output is hinged on one input. if you need to do five things in each case, then you have to use case, but if you just need X to turn into Y, (a 1:1), Look Up Tables in the shape of Objects are ideal.
i imagine a RegExp can work here, i used them on a connect4 game to identify 4 in a row, but the above logic table should work as well or better than what you describe.
That will not quite work as you have it, but you can use sortedHand.join(',') and compare it with [1,1,1,2,5].join(',') which will compare the two arrays and should be true if their contents were the exact same (Be careful with numbers typed as strings!)
To be fair, though, I can't imagine why you would design your logic like that. Even a simple card game has hundreds of thousands of possible hands. You might do better using underscore.js's collection managing functions as it will be simpler, and just a better practice.
There are 1274 possible combinations of 5 cards in a regular deck. Listing them all out in a switch statement is completely ridiculous. Why not just have a function count any duplicates to check for 2,3,4-of-a-kinds and then check for straights? (Your array doesn't show suit so I'm assuming you are leaving it out).
But if you really want to do it that way, you could use a string. Strings work with switches, and you can even use them like arrays. e.g. "123"[0] == '1'. You can change them back and forth user functions like parseInt.
Since no one suggested this, use a for loop and count the number of cards with exactly the given value. Having such a function you can call 'cardCount = count(sortedHand, cardNumber)'. And of cause looping through all possible card-numbers will give you the hands.
Since a given player can only have 1x2, 2x2, 1x3, 1x3+1x2, 1x4 or straights/streets, you can return an array of all hits being arrays/objects stating the count and the cardNumber involved. So [{2, 5}, {3, 6}] for a full house.
Basically I'm creating a program similar to a blackjack program where two cards are dealt according to a random number generator, with the possibility of the same card being dealt twice at the same time (i.e. two Queen of hearts showing up at once) and I want to create a counter of how many times that event occurs, but when I implement an if statement, it affects the outcome so that the two cards are ALWAYS the exact same...can someone tell me what I'm doing wrong here? The code is as follows:
function dealHand() {
var randomCardOne = Math.floor ((Math.random() *13) +2);
var randomCardTwo = Math.floor ((Math.random() *13) +2);
if (randomCardOne = randomCardTwo) {identicalCards()};
}
var identicalPairs = 0;
function identicalCards(){
document.getElementById("identical").value=++identicalPairs;
}
You are assigning the value of one card to another
if (randomCardOne = randomCardTwo) {identicalCards()};
should be
if (randomCardOne == randomCardTwo) {identicalCards()};
In the first case you are simply evaluating if randomCardOne is "truthy" after being asigned the value of randomCardTwo.
Consider if you might want to use === instead of == since
2 == '2' // yields true
2 === '2' // yields false
It's not an issue in this case but it might be in others so it's good to be aware of this. I try to stick with === since it is more strict.
You're using =, that's an assignment operator in JavaScript. You should be using ==
e.g.
if (randomCardOne == randomCardTwo) {identicalCards()};