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.
Related
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()]();
I'm going through a collection of DOM elements, and when criteria is found, DOM element gets a CSS class flashMe added to it.
CSS is a 1 second animation - I'm then using a setTimeout to remove the CSS class 1.5 seconds later.
If I use function (varCounter) in the loop, it will use varCounter reference, not value.
So I'm using function (passedIndex = varCounter) which passes a current value, and works great in Firefox.
In WebKit (Chrome & Safari) same code throws: SyntaxError: Expected token ')' on 6th line: function(pIndex=b)
var self=this;
for(var b=0;b<this.someDOMcollection.length;b++){
if(this.someDOMcollection[b].id==someCriteria){
this.someDOMcollection[b].classList.add('flashMe');
setTimeout(
function(pIndex=b){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}
,1500);//end Timeout
break;
}//if
}//b
One way to get around it is to make a separate function, and pass it currently found index value, but ideally I would like to keep it within the same block.
Any help or pointers would be greatly appreciated.
Default values is an ES6 extension and is currently only supported by Firefox.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/default_parameters
The simple solution here would be to store the value in a closure :
var self=this;
for(var b=0;b<this.someDOMcollection.length;b++){
(function(pIndex){
if(this.someDOMcollection[b].id==someCriteria){
this.someDOMcollection[b].classList.add('flashMe');
setTimeout(
function(){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}
,1500);//end Timeout
break;
}//if
})(b);
}//b
function(pIndex=b){ is not valid JavaScript (yet). Use a Immediately-Invoked Function Expression (IIFE), instead:
(function(pIndex){ // Accept a parameter, named `pIndex`.
setTimeout(function(){
self.someDOMcollection[pIndex].classList.remove('flashMe');
}, 1500);
})(b); // Pass `b` to the inner function.
I am looking for a best practice in this hypothetical situation.
In the example below the function changeGallery0() is a unique function that is Not the same as changeGallery1(), changeGallery2(). They can not be modified to solve this. But each function does take the exact same data (newArrayData)
This code seems "ugly" but works properly. It would become more ugly with 20 galleries. I realize some of this problem exists with the calling unique functions, but it helps illustrate my question.
Using a SWITCH case seems to be more proper. But does it have any advantage over this IF based solution? It seems like a "dynamic function name" (does that exist) would make sense?
Thank you!
if (a == 0) changeGallery0(newArrayData);
if (a == 1) changeGallery1(newArrayData);
if (a == 2) changeGallery2(newArrayData);
if (a == 3) changeGallery3(newArrayData);
You could try something like this:
var fn = window['changeGallery' + a];
if (typeof fn === "function") {
fn.apply(null, newArrayData);
}
The first argument to "apply" would be "this" in your function call.
You could do
window["changeGallery" + a](newArrayData);
I think it would be better to use a for loop. You can place functions inside an array.
var funcArray = [function1, function2 , function3, ...];
There is one thing you need to know about this that is how branching will occur with if else or switch.
With if else if a is 0 the first one will be hit and then you miss rest of 3 but still need to check condition.
With switch you will have branches done but actual code will have a break after one and not check rest of conditions.
You can achieve same with if by using else statements like
if a is not 0 then check if its 1 otherwise no need to do so
If a is not 1 then check if its 2 otherwise no need to do so
this would create nested if else statements that are similar to a switch branching and switch would read better in code so use that.
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.
New to javascript, I face many problems.
I read the javascript tutorial at w3cschools.com,
and there are many question marks on my head.
I do not understand what is the difference below:
var name=something;
name=something;
The above two examples also giving something to a name, why 2 different ways?
name=new Array();
name[0]=something0;
name[1]=something1;
is this same with switch?
//switch start
var name=something();
switch(something)
{
case 1:
do something;
break;
case 2:
do something;
break;
default:
do something;
}
//if...else start
var name=something();
if (condition)
{
do something
};
else if (condition)
{
do something
};
else
{
do something
};
what is the different between switch case and else.if ?
i think both 2 is doing the same thing?match condition and then do something?
and the for Loops,while Loops and break Loops ,
both 3 are doing the same thing,but 3 different ways.
can someone tell me what is the different between them?it make me confuse.
and please intro more tutorial for javascript.
many thanks here
For your first question, when u use "var", it defines a local scope to the variable. When you use variables without keywork "var", it means they are global variable. Usually its not a good practice to use global variables.
Also on other IF ELSE parts, you cant have semicolon before ELSE IF block.
Check these links -
Read all articles under JavaScript: http://www.crockford.com/
JavaScript: Scoping and Hoisting: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
JavaScript: Function expressions vs. Function declarations vs. Function statements: http://yura.thinkweb2.com/named-function-expressions/
In answer to your first question:
var name=something;
name=something;
var name
This snippet creates a new variable, called name. It will be refered to in the rest of your code as name, it has been declared.
var name = something
This piece of code assumes that there is a variable declared above it called 'something', and it creates the name variable and assigns it the value of whatever 'soemething' holds at that particular point.
name = something
Without the intitial creation of the variable, this line assumes that the variable has already been declared previously, it is simply assigning that variable the value or something.
Reading
I recommend you read this webpage which appears to have a great introduction to javascript and will answer many more of your questions.
and a quick, easy answer to your switch question. switch is just often cleaner and more readable than a repeated else if block.
You can also do cool stuff like regular expressions in your case (case /awesome|radical/: ...). You will appreciate that later ;)