Why does a non-default last-case execute in JavaScript switch? - javascript

I have (ab)used a switch statement like this:
const foo = figureOutWhatFooIs()
console.log(foo) // 'bar'
switch (foo) {
case 'bar':
console.log('foo = bar')
case 'baz':
console.log('foo = baz')
}
i.e. no break's and no default
I discovered that even when foo = 'bar', the baz case (and incidentally the last case) also executes.
I'm not surprised that the last case was checked but I am surprised that it executed. Thoughts? Thanks!

Checking is done at the start of switch statement, NOT during running case statements.
The case clause works similar to labels and goto/JUMP statements in other languages such as C++1 and Assembly2, which means case 'bar': is nothing more than a label that can be used to "jump" execution to it, but does nothing logical in itself.
So, when a case clause matches, JavaScript "jumps" you to that label, and then runs all statements one by one, ignoring any other case clauses because they're simply labels.
But of course, if there's any break statement along the way, it'll exit switch.
The main reason switch statement does not break by default could be so that it's easier to match multiple conditions like this:
switch (color) {
case 'red':
case 'orange':
case 'blue':
console.log('Colorful!');
break;
case 'black':
case 'white':
case 'gray':
console.log('Black & white!');
break;
default:
console.log('What color is that??');
}
1 https://en.cppreference.com/w/cpp/language/goto
2 https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm

it is because you are not using break, so after running the first case, is going to continue with the others. Make a test, adding another 2 cases, one before 'bar' case and the second after it. The first one isn't going to run when foo = 'bar' (because is before) but the second is going to run, and if you add more cases after the 'bar' case, every one is going to execute if you don't use break. That's why is very important to use in switch

Related

How do simplified if statements work in javascript? [duplicate]

This question already has answers here:
Concise syntax for javascript if statements without curly brackets
(5 answers)
Closed 6 years ago.
Once and awhile I see and try to use an if statement like this:
var boo = true;
if(boo)
console.log("a");
as opposed to :
var boo = true;
if(boo == true){
console.log("a");
}else{
console.log("not true");
}
Is there a way to have an "else" with my first switch statement? How does the compiler even know when to stop? Does it do the conditional logic after a linebreak?
An if is just followed by a statement. A block (which is typically and idiomatically used there) is just a type of statement that wraps up a group of other statements.
Is there a way to have an "else" with my first switch statement?
The same is true of else
if (1)
something();
else
something_else();
How does the compiler even know when to stop?
It allows a single statement.
Does it do the conditional logic after a linebreak?
No, a statement. The line break there just triggers ASI.
The formal syntax for if else is something like:
if statement else statement
The generic "statement" there can be something like a simple assignment expression, a single function call, or a block of one or more statements enclosed in { }. Thus, the { } are not part of the syntactic structure of the if statement. They're part of the general and often-used compound statement. (JavaScript may formally call that something else; it's a common thing however and the name isn't so important. edit A comment notes that it's formally a "block statement", but I think "compound" is more descriptive so I'll leave it in.) A brace-enclosed compound statement contains any number of other statements, but from the outside it comprises just one statement.
The else part of the if statement is optional, so
if statement
is fine too.
Thus, in your examples:
if (boo)
console.log(a);
The console.log(a); is the single statement. In the second example:
var boo = true;
if(boo == true){
console.log("a");
}else{
console.log("not true");
}
there is an else clause, and both the if and the else have compound statements playing the role of the single statement in the formal syntax.
As to exactly how the parser understands that, well, that's a big topic. Suffice to say that programming languages are designed to be as unambiguous as possible, so that the code to parse the raw text of a program can be as simple as possible. Of course, as with anything, no such design is perfect, and in particular JavaScript has syntax features that are surprisingly hard to parse. What we're talking about here, however, isn't one of those. The whole purpose of the { } wrapper around a compound statement is to give the parser a clear signal: here comes a compound statement.
if (condition)
stuff...
else
stuff...
if(true)
alert("A")
else
alert("B")
alternatively
if(false)
alert("A")
else
alert("B")

Nested functions vs. chaining methods vs. a && sequence of functions

Good evening/morning (depending of your place),
I'm a newbie 'developer' (JS/Meteor platform), and every day I discover a new thing about JS. Knowing my low level, It is not that hard...
I'm currently wondering the best way/practice to code a switch(true).
More precisely I have a Switch statement with something like 20 cases.
Currently, I decide not to nest some cases together, I find it less easy to read. So my statement looks like something like this:
switch()
case 1
case 2
case 3
case 4
case 5
case 6
...
default
Instead of something like:
switch()
case 1
if
elseif
else
//or
case 2
switch()
case 2.1
case 2.2
My question is: each case tests something like 5+ functions. So a case is basically written this way:
case ( function1()
&& function2()
&& function3() == null
&& typeof abc[1] === 'undefined'
&& function4() === 'xyz') : //etc...
Is there a better way to chain functions?
I'm currently looking at chaining method in a jQuery way: function().function2().function3()... But I don't know if it exits a better way to deal with this kind of situation.
I will be delighted to get your feedback/advice and any reading/lecture you would recommend. I also hope this question is "right" for SO.
Thank you very much.
You shall always strive against small functions to increase readability. It might be a good idea to group function calls in new functions. The faster you can determine what a function does the better. Try to only have things relevant to the current function, for example:
You are supposed to fetch a lot of information about a person but the information is spread into different sources forcing you to have one function for name, one for age, one for shoe size and so on.
Instead of writing it like
case 1:
var person = {
name: getName(),
age: getAge(),
showSize: getShowSize()
};
You could write it like
case 1:
var person = getPerson();
And the the getPerson function
function getPerson() {
return {
name: getName(),
age: getAge(),
showSize: getShowSize()
}
}
In your 20 cases I'm sure there are logical groups of functions that is used in several cases. Try to group them together if they have any logical connections. With a switch as large as with 20 cases I would try to not write to much code in every case since it would probably make it difficult to see what the function does.
I hope I got your problem and at least gave you some advices you find useful.

Javascript switch with global variable

I'm trying to use a global variable with a switch statement but the value of the variable is not changing. Perhaps a scope problem?
I need a switch statement to cycle through each case one by one, but the "i" variable keeps resetting to 1 every time I view it in the console.
Why is this happening?
THE CODE
var i = 0;
switch(i){
case 0:
i+=1;
console.log(i);
break;
case 1:
i+=1;
console.log(i);
break;
}
and so on...
edit: Great support from everybody below, thank you very much.
This behaves this way, because switch is working like:
Before iteration it stores your condition.
After that it takes decision.
Switch is not like "use it async", it is running only 1 time when it is invoked.
You can workaround this for example by using loop.
Use:
switch (Number(i)) {
// cases
}
I had the same problem and had already corrected this once, but had forgotten.

Can this be written in a switch statement?

I am writing a Safari extension, and would like to detect what page (url) I am currently on, and do things accordingly.
Right now my code looks something like:
if (linkHas("facebook.com")) {...}
else if (linkHas("google.com")) {...}
else if (linkHas("yahoo.com")) {...}
where linkHas() is a function that basically returns 1 if it has the parameter, and 0 otherwise.
Is it possible to write this one single switch statement? I've read somewhere that switch statements are implemented as hash tables if there are more than 5 options. For a small script like mine, the speed probably doesn't really matter much here, I'm really just trying it as an exercise.
The simple, and straight answer is no.
The switch expression has to be/return a value, that is evaluated against the value of each case. As JCOC611 has actually demonstrated, it can be done, but I beg you, don't :)
There is probably definitely a better way of implementing what you're after, but that wasn't your question, so I'll leave it at that.
EDIT
In fact, let me show you a better way.
function doFacebookStuff() {
console.log('Hello Facebook!');
}
function doGoogleStuff() {
console.log('Hello Google!');
}
function doYahooStuff() {
console.log('Hello Yahoo!');
}
var domainActions = {
'facebook.com': doFacebookStuff,
'google.com': doGoogleStuff,
'yahoo.com': doYahooStuff
}
var matched = Object.keys(domainActions).filter(function(domain) {
if (linkHas(domain)) {
domainActions[domain]();
return true;
}
});
console.log('matched domains:', matched);
You can also replace .filter() with .some(), to have it stop at the first match it finds.
Edit: Disclaimer: the following is something you should not do, but is there for reference purposes only. Don't let people tell you you can't, but listen when they say you shouldn't.
The very naive way:
switch(true){
case linkHas("facebook.com"):
// ...
break;
case linkHas("google.com"):
// ...
break;
case linkHas("yahoo.com"):
// ...
break;
}
This has absolutely no performance benefits though. In fact, it might be slower if all the functions are evaluated before the equality tests are performed.
The long way would be to refactor linkHas to be getLinkDomain and check on whatever that returns.
In fact, lets do that. Using the convenient function extractDomain, written by lewdev, you can:
var domain = extractDomain(link);
switch(domain){
case "facebook.com":
// ...
break;
//...
}
Create an "enumeration" of domains to avoid magic strings.
Create a function "getDomain" that returns one of said enumeration.
Create your own hash table called "actions" using an object literal, keyed on said enumeration values. Hash table values can be functions containing the logic to run for that key.
Then write:
actions[getDomain()]();

Firebug debugging confusing in JavaScript switch statement

I have the following switch statement in JavaScript :
switch(scrollable.direction){
case "top" :
break;
case "left" :
break;
case "right" :
scrollable.select("."+lineCssClass).invoke("setStyle", {float: "right"});
break;
case "bottom" :
alert("Bottom scrolling not implemented yet ! Sorry !");
return;
}
(the "invoke" bit is prototype.js, but it's no relevant to the question anyway)
It is inside a function. I want that if the value is "bottom" a message is displayed and the method execution stops.
The problem is that if the value is e.g. "top", the break is executed, but the execution jumps to the return; statement instead of exiting the switch statement.
I actually solved the problem by adding an additionnal break; after the return, which is actually dead code since it can never be executed.
But I would be curious to know why it executed the "return" in the first place ?
Edit: I am sorry, the "return" wasn't actually executed. I was stepping through the code using Firebug and it actually stepped on and highlighted the "return" line, but it wasn't executed.
There are other problems in my code that cause it not to work as expected, and I was wrongly blaming this.
My bet is that your scrollable.direction is giving you a worng value that is not a real direction.
Add a default clause to your switch statement (as you should always do, btw) to check it out
switch(scrollable.direction){
/*...*/
case "bottom" :
alert("Bottom scrolling not implemented yet ! Sorry !");
return;
default:
console.log(scrollable.direction, 'is not a direction');
break;
}
As I said in the edit I made to the question, the problem was actually not that the return; was executed, but that Firebug gave the impression it was when I went step by step through the switch statement.
Alsot, after some more tests, I can reproduce this weird thing only when I enclose the switch/case statement in a try block.
As missingno suggested I will leave this question in case other people are confused by this behaviour of Firebug.
Similar sort of issue occurred with me while using Firebug but on the IF statement.
if(multiship == true)
{
// do something
}
else
{
// do something
}
The debugger showed that the script execution took the if path instead of having multiship variable equal to false.

Categories