Passing on function with switch dynamically - javascript

I am new to javascript and I am trying to figure out how to dynamically pass on functions with switch?
For example, I can pass on function manually like following
var select =1 ;
function add (val){ return val+512};
function subtract(val) {return val-300};
function multiply(val){return val*584};
var value = 290;
var text = `the value is ${add(value)}`
console.log(text);
How can I pass on a function with a switch based on the select value? The following does not work.
var select =1 ;
function add (val){ return val+512};
function subtract(val) {return val-300};
function multiply(val){return val*584};
var value = 290;
//switch statement
switch(select){ case 1: add(value); break; case 2: subtract(value); break; case 3: multiply(value); break};
var string = `this value is ${switch(select){ case 1: add(value); break; case 2: subtract(value); break; case 3: multiply(value); break};}`
console.log(string)

I suggest moving the switch bloc inside a function, like the following:
var select = 1;
function add(val) { return val + 512 };
function subtract(val) { return val - 300 };
function multiply(val) { return val * 584 };
var value = 290;
var string = `this string in ${chooseFunction(select, value)}`
console.log(string)
function chooseFunction (select, value) {
// switch statement
// Note that the break statement is optional
// if you return a value at the end of a case block
switch (select) {
case 1: return add(value);
case 2: return subtract(value);
case 3: return multiply(value);
}
}

You write a function that has the switch returning the result of calling functions based on the input, and use that in the template string.
function add(val) {
return val + 512;
}
function subtract(val) {
return val - 300;
}
function multiply(val) {
return val * 584;
}
function run(value, select) {
switch (select) {
case 1: return add(value);
case 2: return subtract(value);
case 3: return multiply(value);
}
}
const value = 290;
const string1 = `This string is ${run(value, 1)}`;
const string2 = `This string is ${run(value, 2)}`;
const string3 = `This string is ${run(value, 3)}`;
console.log(string1);
console.log(string2);
console.log(string3);

You cannot pass a switch directly, as you cannot pass a if statement without a ternary operator. You need to encapsulate your switch statement in a function like this :
var select =1 ;
function add (val){ return val+512};
function subtract(val) {return val-300};
function multiply(val){return val*584};
var value = 290;
const getValue = (s, v) => {
switch(s) {
case 1:
return add(v);
case 2:
return subtract(v);
case 3:
return multiply(v);
};
}
var string = `this value is ${getValue(select, value)}`
console.log(string)
An other way to do this is to put your functions into an array with the index referencing the choice :
var select =1 ;
function add (val){ return val+512};
function subtract(val) {return val-300};
function multiply(val){return val*584};
var value = 290;
const fn = [add, subtract, multiply];
var string = `this value is ${fn[select - 1](value)}`
console.log(string)

Related

Call a result of a function inside a function

I want to bring out the results of a function that is within another function. When I try to print or return results it only brings out the result of the function "Sum".
let readlineSync = require("readline-sync");
let a = readlineSync.question(
"Choose an operation: Sum or Substraction: "
);
let param1 = parseInt(readlineSync.question("Value 1: "));
let param2 = parseInt(readlineSync.question("Value 2: "));
chosenFunction();
function Sum() {
return param1 + param2;
}
function Substraction() {
return param1 - param2;
}
function chosenFunction() {
let result;
if (a = 'Sum') {
result = console.log (Sum());
} else if (a = 'Substraction') {
result = console.log ( Substraction());
}
return result
}
It's an invalid usage,when you assign value,you need to remove console.log
Also need to change = to == when compare values
So change
result = console.log (Sum());
result = console.log ( Substraction());
to
result = Sum();
result = Substraction();
Full code
function chosenFunction() {
let result;
if (a == 'Sum') {
result = Sum();
} else if (a == 'Substraction') {
result = Substraction();
}
return result
}
You need to use == or ===. You are actually changing your values, not comparing, when using = as in else if (a = 'Substraction').
if (a === 'Sum')
else if (a === 'Substraction')

Syntax Error: Unexpected Identifier - Higher Order Function that Returns a Function in JavaScript

Putting together a simple script to test out a more complex math operation in JavaScript. The goal of the function is to return a function that will add an input by x.
For example:
const addByTwo = addByX(2);
addByTwo(1); //should return 3
addByTwo(2); //should return 4
addByTwo(3); //should return 5
const addByThree = addByX(3);
addByThree(1); //should return 4
addByThree(2); //should return 5
Here's my function:
function addByX (input) {
function output () {
return input + 2;
}
return output;
}
const addByTwo = addByX(2);
Error:
I'm currently getting: Syntax Error: Unexpected identifier
Test code:
console.log(addByTwo(1));
console.log(addByTwo(2));
On what line are you getting a SyntaxError? Your definition of addByX appears to be incorrect. It should be as follows:
function addByX(x) {
function output(input) {
return input + x;
}
return output;
}
const addByTwo = addByX(2);
addByTwo(1); //should return 3
addByTwo(2); //should return 4
addByTwo(3); //should return 5
const addByThree = addByX(3);
addByThree(1); //should return 4
addByThree(2); //should return 5
console.log(addByTwo(1));
console.log(addByTwo(2));
define your addByX function like this:
function addByX (x) {
return function output (input) {
return x + input;
}
}
const addByTwo = addByX(2);
const addOne = addByTwo(1);
console.log(addOne);
you can write a function like this
Function:
function addByX(fun_name, input)
{
var add = 0;
if (fun_name == "Two") add=2;
else if (fun_name == "Three") add = 3;
return add + input;
}
Usage:
addByX("Two", 1);
addByX("Three", 1);

Javascript scope variable to switch case?

In C you can scope a variable to a switch case, like this.
With javascript I get unexpected token using the following:
const i = 1
switch (i) {
// variables scoped to switch
var s
var x = 2342
case 0:
s = 1 + x
break
case 1:
s = 'b'
break
}
Is there another way to do this or should I just declare my variables outside the switch?
EDIT:
This is a workaround I considered but it didn't end up working. The reason being that each case has its own scope.
const i = 1
switch (i) {
case i:
// variables scoped to switch
var s
var x = 2342
case 0:
s = 1 + x
break
case 1:
s = 'b'
break
}
some alternative:
/* curly braces inside the case */
const i = 1
switch (i) {
case 0: {
let x = 2342;
let s = 1 + x;
console.log(x+' & '+s+' from inside');
} break;
case 1: {
let x = 2342;
let s = 'b';
console.log(x+' & '+s+' from inside'); /* 2342 & b from inside */
} break;
}
console.log(x+' & '+s+' from outside'); /* Uncaught ReferenceError */
or
/* curly braces outside the switch */
const i = 1
{
let x = 2342;
let s;
switch (i) {
case 0:
s = 1 + x;
break;
case 1:
s = 'b';
break;
}
console.log(x+' & '+s+' from inside'); /* 2342 & b from inside */
}
console.log(x+' & '+s+' from outside'); /* Uncaught ReferenceError */
Since var creates variables at function scope anyway, using it is pretty pointless. For this to work at a granularity below function scopes you'll have to use let and a browser/compiler which supports it, and then introduce a new block which you can scope things to (within switch it's simply invalid syntax):
if (true) {
let s;
switch (i) {
...
}
}
This scopes s to the if block, which for all intents and purposes is identical to the "switch scope" here.
If you cannot support let, you'll need to use an IIFE:
(function () {
var s;
switch (...) ...
})();
No, this is invalid syntax. A case or default statement is expected within a switch. You can check the specification here: http://www.ecma-international.org/ecma-262/5.1/#sec-12.11
You can also try entering your code in a JSLinter and see that this an error: http://jslint.com/
Expected 'case' and instead saw 'var'.
The workaround that you're considering would be the same thing as putting them outside the switch statement. Remember, var has function-level scope, not block-level scope. That means they are bound to the entire function containing the switch. You should declare them outside of the switch because that is where they are accessible.
const i = 1;
var s;
var x = 2342;
switch (i) {
case 0:
s = 1 + x;
break;
case 1:
s = 'b';
break;
default:
break;
}
console.log("s is " + s);
It should be declared outside the switch. The below might help:
var i = 1, x = 2342;
var s;
switch (i)
{
case 0:
s = 1 + x;
break;
case 1:
s = 'b';
break;
}
console.log("s is " + s);
JavaScript defines 3 levels of scope:
Global - Anything not delcared in a function
Function - Anything declared in a function using the var keyword
Block - Anything declared in a block container ({}) using let
So, to creae a scope an entire construct, you have two choices: Function or Block
In order to get the the behavior you are looking for with a function:
const i = 1
function doSwitch(data){
// variables are not scoped to switch, but are
// scoped to the function, which only contains
// the switch.
var s;
var x = 2342;
switch (data) {
case 0:
s = 1 + x;
break;
case 1:
s = 'b';
break;
default:
s = "other";
}
console.log("s is " + s)
}
doSwitch(18);
Or, in order to get the functionality with a block using let
const i = 1;
// Wrapping the switch in its own block allows for let to work:
{
// variables are not scoped to switch, but are
// scoped to the function, which only contains
// the switch.
let s;
let x = 2342;
switch (i) {
case 0:
s = 1 + x;
break;
case 1:
s = 'b';
break;
default:
s = "other";
}
console.log("s is " + s)
}
// Test:
console.log(s, x); // ReferenceError

Having Trouble Understanding Javascript Methods

This is my current assignment :
Add a method that will increase the value of one of the numeric properties.
Add a method that will decrease the value of the same numeric property.
Create a for loop after creating an instance of the character. The loop will iterate 100 times.
Inside the loop call one of the methods based on a random number from zero to 3. Using a switch statement, if the value is 0 then call the method that losses; 1 don’t call anything; 2 call the method that gains.
Here is my current coding. I know I'm doing something wrong. I just can't figure out what I am doing wrong with the switch statement.
var BR = "<br />";
function person(name, sandwiches) {
this.name = name;
this.sandwiches = sandwiches;
function jump() {
var text = " leaps over an obstacle.";
return fname + text;
}
function run() {
var text = " runs as fast as they can";
return fname + text;
}
function dodge() {
var attack = math.random();
var att = math.round(attack);
var defense = math.random();
var def = math.round(defense);
if(att > def) {
return "You missed";
}
else {
return "You dodged";
}
}
function date() {
var today = new Date();
return today.toDateString();
}
function shout() {
var word = "Oh no";
return word.toUpperCase();
}
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
this.loseSandwich = function (sandwiches) {
sandwiches = sandwiches - 1;
return sandwiches;
};
}
var character = new person("Jerry", 1);
for(i=0; i < 100; i++) {
var random = Math.floor(Math.random() * 3);
switch(random) {
case 0:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
break;
case 1:
break;
case 2:
character.addSandwich(character.sandwiches);
break;
}
}
document.write("Name: " + character.name + BR);
document.write("Sandwiches: " + character.sandwiches + BR);
Math.floor(Math.random() * 3) is not what you want.
You want something like Math.random() % 3 to get 0, 1, or 2 every single time
Not sure if this is your problem, but it is at least one of them;
In a few places you have a lowercase math, for example:
function dodge() {
var attack = math.random();
JavaScript is case-sensitive, and it should be Math.random() not math.random()
Another issue is that these functions:
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
do not change the number of sandwiches. You get in a value of sandwiches, add or subtract 1, then return that changed number, but never use the returned result.
You are only changing the value of the variable that was passed in, not changing the number of sandwiches on the instance of the person.
Note that this.sandwiches (the variable on the instance of a person) is not the same variable as sandwiches (the function argument)
I dont think there is any reason to pass the number of sandwiches into those functions, and they could just do:
this.addSandwich = function () {
this.sandwiches = this.sandwiches + 1;
};
or more simply:
this.addSandwich = function () {
this.sandwiches++;
};
Another problem here:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
The console.log statement is trying to log sandwiches but that is not a variable at that point. You probably wanted console.log(character.sandwiches); However this wouldn't cause an exception, it would just always log undefined.

How to parse pure functions

Let's say you have the following function
var action = (function () {
var a = 42;
var b = 2;
function action(c) {
return a + 4 * b + c;
}
return action;
}());
// how would you parse action into it's serialized LISP / AST format?
var parsed = parse(action);
Is it possible to have a function that takes a reference to the function action and outputs say the LISP format (lambda (c) (plus (plus 42 (multiply 4 2)) c))
We're allowed to put some restrictions on what action can be.
the body should only be a single expression
it should be a pure function
any free variables are constants
The main question is given a function you can invoke with a range of inputs and it's source code can you discover the correct value to substitute the free variables with?
For the above example you know that a and b are constant and you could intellectually plot the output for a few values and see the pattern and then just know what the constants are.
Question:
How would you write a function that takes a function reference and it's source code and produces some form of AST for the function with any free variables substituted for their run-time values.
An example of an AST format would be the LISP equivalent of the code.
I basically want to serialize and deserialize the function and have it behave the same
It should be noted that the problem becomes trivial if you pass { a: a, b: b } to the analysis function. That would be cheating.
Use-case:
I want to generate a language agnostic form of a pure JavaScript function so I can effectively pass it to C++ without requiring the user of my library to use a DSL to create this function
Let's imagine you had a database driver
var cursor = db.table("my-table").map(function (row) {
return ["foo", row.foo]
})
You want to determine at run-time what the function is and convert it into an AST format so that you can use your efficient query builder to convert it into SQL or whatever query engine your database has.
This means you don't have to write:
var cursor = db.table("my-table").map(function (rowQueryObject) {
return db.createArray(db.StringConstant("foo"), rowQueryObject.getProperty("foo"))
})
Which is a function the DB library can execute with a query object and have you build the query object transformation without verbose methods.
Here is a full solution (using catalog of variables which is accessible by the parse function):
var CONSTANTS = {
a: 42,
b: 2,
c: 4
};
function test() {
return a + 4 * b + c;
}
function getReturnStatement(func) {
var funcStr = func.toString();
return (/return\s+(.*?);/g).exec(funcStr)[1];
}
function replaceVariables(expr) {
var current = '';
for (var i = 0; i < expr.length; i += 1) {
while (/[a-zA-Z_$]/.test(expr[i]) && i < expr.length) {
current += expr[i];
i += 1;
}
if (isNumber(CONSTANTS[current])) {
expr = expr.replace(current, CONSTANTS[current]);
}
current = '';
}
return expr;
}
function isNumber(arg) {
return !isNaN(parseInt(arg, 10));
}
function tokenize(expr) {
var tokens = [];
for (var i = 0; i < expr.length; i += 1) {
if (isWhitespace(expr[i])) {
continue;
} else if (isOperator(expr[i])) {
tokens.push({
type: 'operator',
value: expr[i]
});
} else if (isParentheses(expr[i])) {
tokens.push({
type: 'parant',
value: expr[i]
});
} else {
var num = '';
while (isNumber(expr[i]) && i < expr.length) {
num += expr[i];
i += 1;
}
i -= 1;
tokens.push({
type: 'number',
value: parseInt(num, 10)
});
}
}
return tokens;
}
function toPrefix(tokens) {
var operandStack = [],
operatorStack = [],
current,
top = function (stack) {
if (stack) {
return stack[stack.length - 1];
}
return undefined;
};
while (tokens.length) {
current = tokens.pop();
if (current.type === 'number') {
operandStack.push(current);
} else if (current.value === '(' ||
!operatorStack.length ||
(getPrecendence(current.value) >
getPrecendence(top(operatorStack).value))) {
operatorStack.push(current);
} else if (current.value === ')') {
while (top(operatorStack).value !== '(') {
var tempOperator = operatorStack.pop(),
right = operandStack.pop(),
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
operatorStack.pop();
} else if (getPrecendence(current.value) <=
getPrecendence(top(operatorStack).value)) {
while (operatorStack.length &&
getPrecendence(current.value) <=
getPrecendence(top(operatorStack).value)) {
tempOperator = operatorStack.pop();
right = operandStack.pop();
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
}
}
while (operatorStack.length) {
tempOperator = operatorStack.pop();
right = operandStack.pop();
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
return operandStack;
}
function isWhitespace(arg) {
return (/^\s$/).test(arg);
}
function isOperator(arg) {
return (/^[*+\/-]$/).test(arg);
}
function isParentheses(arg) {
return (/^[)(]$/).test(arg);
}
function getPrecendence(operator) {
console.log(operator);
switch (operator) {
case '*':
return 4;
case '/':
return 4;
case '+':
return 2;
case '-':
return 2;
default:
return undefined;
}
}
function getLispString(tokens) {
var result = '';
tokens.forEach(function (e) {
if (e)
switch (e.type) {
case 'number':
result += e.value;
break;
case 'parant':
result += e.value;
break;
case 'operator':
result += getOperator(e.value);
break;
default:
break;
}
result += ' ';
});
return result;
}
function getOperator(operator) {
switch (operator) {
case '+':
return 'plus';
case '*':
return 'multiplicate';
case '-':
return 'minus';
case '\\':
return 'divide';
default:
return undefined;
}
}
var res = getReturnStatement(test);
console.log(res);
res = replaceVariables(res);
console.log(res);
var tokens = tokenize(res);
console.log(tokens);
var prefix = toPrefix(tokens);
console.log(prefix);
console.log(getLispString(prefix));
I just wrote it so there might be some problems in the style but I think that the idea is clear.
You can get the function body by using the .toString method. After that you can use regular expression to match the return statement
(/return\s+(.*?);/g).exec(funcStr)[1];
Note that here you must use semicolons for successful match! In the next step all variables are transformed to number values using the CONSTANTS object (I see that you have some parameters left so you may need little modifications here). After that the string is being tokenized, for easier parsing. In next step the infix expression is transformed into a prefix one. At the last step I build a string which will make the output looks like what you need (+ - plus, - - minus and so on).
Since I'm not sure you're able to get the method's body after having invoked it, here is an alternative solution:
var a = 42;
var b = 2;
function action(c) {
return a + 4 * b + c;
}
/**
* get the given func body
* after having replaced any available var from the given scope
* by its *real* value
*/
function getFunctionBody(func, scope) {
// get the method body
var body = func.toString().replace(/^.*?{\s*((.|[\r\n])*?)\s*}.*?$/igm, "$1");
var matches = body.match(/[a-z][a-z0-9]*/igm);
// for each potential var
for(var i=0; i<matches.length; i++) {
var potentialVar = matches[i];
var scopedValue = scope[potentialVar];
// if the given scope has the var defined
if(typeof scopedValue !== "undefined") {
// add "..." for strings
if(typeof scopedValue === "string") {
scopedValue = '"' + scopedValue + '"';
}
// replace the var by its scoped value
var regex = new RegExp("([^a-z0-9]+|^)" + potentialVar + "([^a-z0-9]+|$)", "igm");
var replacement = "$1" + scopedValue + "$2";
body = body.replace(regex, replacement);
}
}
return body;
}
// calling
var actionBody = getFunctionBody(action, this);
// log
alert(actionBody);
Prints:
return 42 + 4 * 2 + c;
DEMO
You would then have to implement your own function toLISP(body) or any function else you may need.
Note that it won't work for complex scoped variables such as var a = {foo: "bar"}.

Categories