Javascript: change test() method name - javascript

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);
}

Related

Replacing multiple parts of a string with switch cases js

How would I get the switch to work, such that both cases, when relevant (like below), occur? I can add return to one of the case changes and get it to work for that one, but what if I have multiple cases like below? .replace requires I assign the new value to a new variable....but how do I get that to work in a loop? I don't want to use regex/regular expressions, I want to use a switch as follows, what options do I have to get this to work?
function convertText(str) {
for (let el of str) {
switch(el) {
case "&":
str.replace("&","on") //how to fix this line...?
case "G":
str.replace("G","key") //how to fix this line...?
break;
}
}
return str
}
console.log(convertText("D&G"));
//donkey
Replace returns a new string; it does not replace the value in the string you call it on. Maybe what you want is another string variable that you modify and then return, like so:
function convertText(str) {
let result = str;
for (let el of str) {
switch(el) {
case "&":
result = result.replace("&","on");
// you may want another break here, unless fall-through is your desired behavior
case "G":
result = result.replace("G","key");
break;
}
}
return result;
}
console.log(convertText("D&G"));
You are still using replace. But you could take a new string and add the value if a cetain character is found or add the actual character to the result.
function convertText(str) {
let result = '';
for (let el of str) {
switch (el) {
case "&":
result += "on";
break;
case "G":
result += "key"
break;
default:
result += el;
}
}
return result;
}
console.log(convertText("D&G"));

Beginner applying ternary operator in Javascript for Pig Latin, but can't figure why it doesn't work

I'm stuck figuring out why the ternary operator won't return the negative output, and can't really figure out why. Here's the code:
function translatePigLatin(str) {
let reg=/[aeiou]/gi;
let firstVowel = str.indexOf(str.match(reg)[0]);
//console.log(firstVowel);
return str.match(reg) == 1 ? play(str) : str + "ay";
function play(str) {
if(str[0].match(reg)){
return str+"way";
}else if(str[1].match(reg)){
return str.slice(1) + str[0]+ "ay"
} else if(str.match(reg)!==null){
return str.slice(firstVowel) +str.slice(0,firstVowel)+"ay";
} else {
return str+"ay";
}
}
}
console.log(translatePigLatin("consonant"));
console.log(translatePigLatin("eight"));
console.log(translatePigLatin("glove"));
console.log(translatePigLatin("hmm"));
The last test with "hmm" results in error : "TypeError: str.match(...) is null".
I feel better understanding of what null means here could help, but unsure if it makes sense, and how to do so.
How might I better understand this, and make it work? Thanks!
There is no match for the word "hmm", since there is no vowel with that string. You'll have to conditionalize your function to return a proper result. I updated the code below.
I took out your else if since you're returning a value in each condition anyway, so it wouldn't read any of the code after returning.
I didn't see a reason for two encapsulated functions.
I used template literals as well.
function translatePigLatin(str) {
const reg = /[aeiou]/gi;
const match = str.match(reg);
const firstVowel = match ? str.indexOf(match[0]) : null;
if (!firstVowel) {
return `${str}ay`;
}
if (str[0].match(reg)) {
return `${str}way`;
}
if (str[1].match(reg)) {
return `${str.slice(1)}${str[0]}ay`;
}
if (str.match(reg)!== null) {
return `${str.slice(firstVowel)}${str.slice(0,firstVowel)}ay`;
}
};
console.log(translatePigLatin("consonant"));
console.log(translatePigLatin("eight"));
console.log(translatePigLatin("glove"));
console.log(translatePigLatin("hmm"));

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

Javascript Basic algorithm

Return true if the string in the first element of the array contains all of the letters of the string in the second element of the array. No case-sensitivity and order doesn't matter only the letters matter. For ex - ["Hello","hello"] returns true and so does ["Alien","lien"] and also ["Mary", "Aarmy"]. I think you get it. If not return false.
I could solve it with Array.indexOf() === -1 (in the first for loop) but can it work with this code, it's the opposite. I just can't make it return false. Ultimately, I wanna know, can you make it return false without changing the method.
function mutation(arr) {
var split = arr[1].toLowerCase().split("");
var splitSecond = arr[0].toLowerCase().split("");
for(k=0;k<=arr[0].length;k++){
for(i=0;i<=arr[1].length;i++){
if(split[i]===splitSecond[k]) {
return true
}
}
} return false
}
mutation(["hello", "hney"], "");
If using any other method, explain :)
The problem with your code is that you return true; as soon as one letter matches.
What you need to do is check if all letters match, which is easier achieved by checking if any letter doesn't match.
mainloop:
for(k=0;k<=arr[0].length;k++){
for(i=0;i<=arr[1].length;i++){
if(split[i]===splitSecond[k]) {
continue mainloop; // found the letter, move on to next search
}
}
return false; // failed to find letter, fail here
}
return true; // haven't failed yet and end of input reached. Success!
Another alternative would be:
for(k=0;k<arr[0].length;k++) {
if( arr[1].indexOf(split[k]) < 0) {
// letter not found
return false;
}
}
// not failed yet? Excellent!
return true;
function mutation(arr) {
var test = arr[0].toLowerCase(),
chars = arr[1].toLowerCase(),
len=chars.length;
for(var i=0;i<len;i++)
if(test.indexOf(chars[i])==-1) //this char not exist in test string
return false;
return true;//all chars already checked
}
mutation(["hello", "he"]);
https://jsfiddle.net/hb2rsm2x/115/
Here is an interesting way using regular expressions. escapeRegExp was taken from here.
function mutation(arr){
var matcher = new RegExp('[^'+escapeRegExp(arr[1])+']', "i");
return arr[0].match(matcher) === null;
}
function escapeRegExp(s) {
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

Javascript switch statement- very simple, what am I doing wrong?

I'm sure there must be a really simple answer to this, but at the risk of sounding stupid- I can't get this switch statement to work. The input var, 'status' can be either 'public' or 'draft', and I can assure you it is only holding one of those two values as I have alerted it out at various stages, and anyway, the if statement here works. Take a look:
function switch_status(status){
if (status == 'public'){
return false;
} if (status == 'draft') {
return true;
}
^This works, but replacing the 'if' with this 'switch' statement below doesn't work.
switch(status){
case 'public':
return false;
case 'draft':
return true;
}
}
The first one to provide me with the inevitable embarrassingly simple answer wins my accolade!
EDIT: Here is my full code-
$('.status').live('click',
function(){
fullClass = $(this).attr('class');
id = fullClass.split(' ').slice(-1);
status = fullClass.split(' ').slice(-2,-1);
var newStatus = switch_status(status);
alert(newStatus);
});
function switch_status(status){
// if (status == 'public'){
// return false;
// } if (status == 'draft') {
// return true;
// }
switch(status){
case 'public':
return false;
case 'draft':
return true;
}
}
You're passing status as an array of one string (the result of slice) rather than as just a string.
When you check equality between your array and your string, it appears that coercion is causing the equality check to work. But coercion doesn't happen in a switch statement.
If I change
status = fullClass.split(' ').slice(-2,-1);
to
status = fullClass.split(' ').slice(-2,-1)[0];
then it works fine.
I suspect this problem is occuring due to type conversion.
Javascipt is generally a loosely typed language. The if statement you used earlier used a loose == comparison. This worked just fine.
However, switch statements are a different matter. For the case to be a match, the data types must match. In other words, the status must be converted to a string before it is passed to the switch statement.
I used a .each in a jquery loop and compared value to 'this'; I could clearly see that 'this' had the correct value if I used console.log. It worked in the if/else logic but failed in the switch/case logic.
The solution is:
var obj = this.toString();
switch(obj){
case 'one': ...
case 'two': ...
}
By forcing the 'this' to a string type, the logic in the switch now works.

Categories