Can this be written in a switch statement? - javascript

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

Related

How can I detect if two functions are the same (in a deep-equal sense)

What I need to do
I need to detect whether two objects are the same. By same I mean deep-equal: different objects that look and behave the same are the same to me. For instance {} is the same as {}, even though {} != {}.
I need to do this on Node.js.
Problem
This has been easy with most types I handle (undefined, null, numbers, NaN, strings, objects, arrays), but it's proving really hard with functions.
For function I would consider two functions to be the same if their name and code is identical. In case the functions are closures, then the variables they capture need to be the same instance.
I don't know how to implement that.
Attempted solutions
These are all the approaches I could think of to compare functions, but they all have issues:
Comparing the function with == or === doesn't work, of course. Example ()=>0 != ()=>0, but they should be the same.
Comparing the function name doesn't work, of course. Example: ()=>0 === ()=>1 when they shouldn't be the same.
Comparing the function's code (as reported by Function.prototype.toString) doesn't work:
const fnFactory=(n)=>{ return ()=>n; };
const fn1=fnFactory(0);
const fn2=fnFactory(1);
fn1.toString() === fn2.toString()
But they shouldn't be the same.
Compare the functions' code. If it's the same, parse it and detect whether the function has any captured variables, if it doesn't, the functions are the same.
This solution however would be unbearably slow. Besides it still doesn't work for different functions that capture the same instances of variables.
What I need this for (example)
I need this in order to implement a factory function like this (this is just a minimal example, of course):
// Precondition:
// "factoryFn" is called only once for every value of "fn"
// the result is then reused for every future invocation.
const storage=new MagicStorage();
function createOrReuse(fn, ...opts)
{
if(storage.has(fn, ...opts)){
return storage.get(fn, ...opts);
}
else{
const data=factoryFn(...opts);
storage.set(data, fn, ...opts);
return data;
}
}
Then I want to use it in several places around my code. For instance:
function f1(n) {
// ...
const buffer=createOrReuse((n)=>new Buffer.alloc(n*1024*1024), n);
//...
}
function f2(){
//...
emitter.on('ev', async()=>{
const buffer=await createOrReuse(()=>fs.readFile('file.txt'));
// ...
});
//...
}
Of course there are other ways to achieve the same result: For instance I could store the allocated values in variables with a lifetime long enough.
However similar solutions are much less ergonomic. I wish to have that small createOrReuse function. In other languages (like C++) such a createOrReuse could be implemented. Can I not implement it in Javascript?
Question
Is it possible to implement the function-comparison logic I need in pure JavaScript? I can use any ES version.
Otherwise is it possible to implement it as a native module for Node.js?
If yes, Is there any Node.js native module that can be used to achieve what I need?
Otherwise, where can I start to develop one?

Cleanest way to set up a chain of fallbacks?

So, I am geocoding addresses from the Google Places API. There are 38 Google address component types, and we have ~5 in-house address component types, so I need a system of mapping a number of Google types to our in-house types, with fallbacks.
For example:
var neighbourhood = googleResponse.neighborhood || googleResponse.sublocality_level_2 || googleResponse.sublocality_level_1
What is the best/cleanest/most efficient way to do this? Basically, I need to assign a var to some returned value, unless that returned value is undefined, and then move down the chain.
I think your approach is sound - using the short-circuiting ORs feels a lot cleaner than having some sort of branching statement to me. My two recommendations would be:
You should probably add some kind of hard-coded value (an empty string, perhaps? Depends on your use case) as a final fallback, so that if all of the options aren't found, you don't end up with the variable being set to something unexpected. I think being 100% explicit about all the possible things that could be returned is always a good practice.
I'd recommend pulling that logic out into a function, so that if you want to reuse it elsewhere it'll be more maintainable. Even if you don't think you'll need to use it again, it's still worth doing in case you change your mind later on - having to go through and replace every instance of a piece of code is incredibly tedious! It also makes your code a lot easier to test - you can pass in a hard-coded googleResponse and check that the output matches your expectations.
So my approach would probably look something like this:
function getNeighborhood(googleResponse) {
return googleResponse.neighborhood
|| googleResponse.sublocality_level_2
|| googleResponse.sublocality_level_1
|| "";
}
var neighborhood = getNeighborhood(googleResponse);
EDIT:
In response to your comment, there's a couple of options I can think of for values that have to be concatenated.
If it's just a matter of "everything or nothing", you could write this quite elegantly with a ternary expression:
function getStreet(googleResponse) {
return googleResponse.street_number && googleResponse.route
? googleResponse.street_number + googleResponse.route
: "";
}
However, if you start trying to nest these with fallbacks, it's going to get very unreadable very fast. At that point, you're better off just relying on a if/else if/else - it's a bit long winded, but it's comprehensible, and that's more important in my eyes.
function getStreet(googleResponse) {
if (googleResponse.street_number && googleResponse.route) {
return googleResponse.street_number + googleResponse.route;
}
else if (/* fallback */) {
return /* concat here */;
}
else {
// Make sure to always return a value, even if all of
// the other fallbacks fail!
return "";
}
}

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.

Where to perform argument validation in JavaScript?

Yeah, read properly. In the last time I saw different patterns of argument validation in JavaScript (functions) and wondered which of them would be best-practice. At first I'll show two example code snippets. The first shows an (in my words) "immediate" argument/condition validation and the second one a "delayed" validation. Each of them affect the appearance of following code in different ways. Up to now I always used the "immediate" validation. But slowly I am getting doubtful if it's reasonable to force the whole following code into such conditional blocks. Please tell me what you think and what might be the "best" pattern.
And what about the place where variables are declared? A few times I read, that ALL variables should be declared on to of the method, before they're actually used. Is this correct? Because I think that it is useless to declare variables before it is sure that they'll be actually used (maybe invalid arguments force the throw of an Exception), I moved the variable-declaration-part beyond the argument/condition validation part. Is this advisable?
Thanks!
First example:
if ( colorStops.constructor === Array
&& colorStops.length
&& colorStops.every(function(c) {
return c instanceof ColorStop
}))
{
var privateVar1 = "foo",
privateVar2 = "bar",
privateVar3 = "tutifrutti";
// here goes the code
}
else {
throw new TypeError("GradientCanvasFacade: cannot add Colors; " +
"invalid arguments received");
}
Second example:
if (cg instanceof ColorGradient) {
throw new TypeError("PresetManager: Cannot add preset; " +
"invalid arguments received");
}
var privateVar1 = "foo",
privateVar2 = "bar",
privateVar3 = "tutifrutti";
// here goes the code
// Here goes the code that get executed when no explicit
// return took place ==> all preconditions fulfilled
Since JavaScript variables are scoped to the declaring function and not to the block as most other languages, declaring variables at the beginning of the function makes alot of sense.
function someFunc()
{
if (1==1)
{
var x = 1;
}
else
{
var x = 2;
}
return x
}
Now imagine a function a lot more complex, to me atleast, declaring x at the beginning makes alot of sense. For variables generally bound to a block (like iterator variables or collections) I still declare them in the block though.
I would definitely go for your second example not because it fails earlier, because really it doesn't, but because it's easier to remove and add validations this way without breaking a complicated if structure.
I'd go with the second, simply because it's easier to read. Also, with the first, if your function is very long, someone looking at the bottom, will wonder what that } is for, and have to hop up to the top to see.
Also the scoping of variables is very clear, even for someone who forgets that javascript has weird scoping rules.
Also, as mentioned by Martijn, the second method makes it a lot easier to check for various errors, ie each can have their own if statement and so on.
if (some condition) {
if (some other condition based in the first) {
if (another condition based in 1st and 2nd) {
do_job();
} else?
} else?
} else?
Where to put the else block? After every if or after the last?
It seems absolutely more readable the second choise

Would it be ridiculous to use a switch statement to handle irc server codes?

There are quite a few of IRC server codes
I am working on a small IRC client for Adobe AIR, and I started out by supporting only a few of these initially, and then a switch statement didn't seem like a bad idea. But as I support more and more, the switch statement is getting longer and it feels like it's a little out of control. One issue is that I've kept the low level IRC handling code in a file on its own so that it can be reused. I would like to keep everything in one file. Another issue is that code blocks in the switch statements currently assume to be part of this IRC class and there's frequent use of the this statement. Making changes now would be a lot of work and introduce regressions. The only problem really is my distaste for a long switch statement, otherwise you know it works, and it's kind of easy to read, but not really making it more difficult to maintain. But it's such a long switch statement. And the function that contains the switch statement is obviously long too. ://
One thing I sometimes do in lieu of a switch is that I define functions that are named after the value the switch evaluates. Instead of a switch:
switch ( val ) {
case: "alert":
alert( "yo" );
break;
}
I check to see if a method exists in scope and execute it:
obj.alert = function ( ) {
alert( "yo" );
}
if ( val in obj && isFunction( obj[ val ] ) ) {
obj[ val ]( );
}
But again in this case I've feel like there's a high risk in regressions and I'm not sure it's worth the effort only to avoid having a long switch statement, for the sake of its length.
Why don't you keep a hash (a JavaScript {} object) with the code as the key and the function as the value? Then, for small pieces of code you could use an anonymous function, and for bigger pieces of code you could just have a reference to an already written function. I don't know anything about IRC, but here's a small example:
var CodeHash = {
001: function() { /* Do something... */ },
002: BigImportantObject.someFunction
}
Kind of a bad example, but you get the idea.
Edit: If you believe that you can maintain such a long switch statement easily and without problems, then I think it's ridiculous to rewrite your program just to remove the switch. But I know that I, personally, would much rather maintain a hash table like above than a huge switch statement, for many reasons. So it's up to you. Seems like a rhetorical question if you keep insisting that the only reason you'd rewrite your code is to get rid of the switch statement.
why not keep the switch in a parameter file with predefined exit points along with their arguments
read the file at the startup and keep in in memory

Categories