Can pass a conditional statement as a function argument? - javascript

I have a main function and want to control 2 actions with it. Thereby I pass different variables to the function.
My question is whether I can also pack the condition of an If query into a variable.
For the one action I want to have CurrentImageNumber <= 3 as an if argument and for the other action CurrentImageNumber >= 2 in the if query.
The code would look something like this:
function imageChange() {
CurrentImageNumber = parseInt(CurrentImageID.slice(-1)) // not a static value
if (b) {
// Some fancy Code where var a is used
}
else {
// Some fancy Code where var c is used
}
}
document.getElementById('button-1').onclick = function() {
imageChange(a = 1, b = CurrentImageNumber <= 3, c = -3)
}
document.getElementById('button-2').onclick = function() {
imageChange(a = -1, b = CurrentImageNumber >= 2, c = 2)
}

Yes you could do this, but what actually happens is, the condition is checked and the predicate returns a boolean value which is parsed into the function.
This would be done like so:
doStuff(CurrentImageNumber <= 4);
function doStuff(a) {
if (a) {
// Execute some fancy code
}
}
But what actually happens during runtime is equivalent to this:
Lets say CurrentImageNumber == 0:
const predicateResult = CurrentImageNumber <= 4;
// Here predicateResult is of type boolean and is true
doStuff(predicateResult);
function doStuff(a) {
if (a) {
// Execute some fancy code
}
}

The function needs a parameter variable to get the argument.
doStuff(CurrentImageNumber >= 2)
doStuff(CurrentImageNumber <= 4)
function doStuff(a) {
if (a) {
// execute some fancy code
}
}

Related

How to use Object.prototype.valueOf to differ return type as a result of coercion in equal value and equal type operator?

A question says to make a sum function that meets the required output as:
My question is, under the circumstance, is it possible to reach the result?
const sum1 = sum(1)
sum1(2)() // return 3
sum1(3)() // return 4
// call directly without assigning to a variable
sum(1)(2)(3)() // return 6
sum(5)(-1)(2)() // return 6
sum(1)(2)(4) == 7 // true
sum(1)(2)(4) === 7 // false
And the definition to the sum function:
/**
* #param {number} num
*/
function sum(num) {
// your code here
}
It also hints that a decent understand of Object.prototype.valueOf() is crucial.
I write something like the code below, also a script for testing and to show my perspective about the required returns. I think Object.prototype.valueOf works when I call the return for as a primitive type, especially a value. (Refers to ECMAScript spec)
My opinion about the question are:
To meet the test case - sum(1)(2)(4) == 7 -> true, useSum.prototype.valueOf is necessary, but I found that I have to call new for make it work. However, this operation also results an object instead of a function.
Then I use conditionals to return function if there is an argument or to return plain value.
While I passed some test cases, the test case - sum(1)(2)(4) == 7 -> true turn to be failed.
I also failed in the cases to run sum1(3)() === 4 after running sum1(2)() === 3. The this.accumulator does not know that it's came from sum1 which has an initial base of 1.
Dealing with the problem than raising another problem for this.accumulator leaves value that affect the initial value in calc the test cases: sum(1)(2)(3)() === 6, sum(5)(-1)(2)() === 6.
/**
* #param {number} num
*/
function sum(num = 0) {
if (this.accumulator) {
this.accumulator += num;
} else {
this.accumulator = num;
this.init = num;
}
const that = this
function useSum(isEnd) {
if (!isEnd) {
return (addend) => sum(addend)
}
return that.accumulator
}
if (num) {
useSum.prototype.valueOf = function() {
return that.accumulator;
}
const result = new useSum(false);
return result
}
const result = this.accumulator;
this.accumulator = 0;
return result
}
// test function
function expect(caseName, occasion) {
function toBe(result) {
console.log(`test case: ${caseName}`);
if (occasion === result) {
console.log("--> pass\n")
} else {
console.log(`--> fail, expect ${result}, got ${occasion}\n`)
}
return null
}
return { toBe }
}
// test cases from my pespective
const sum1 = sum(1);
expect("sum1(2)() === 3", sum1(2)()).toBe(3)
expect("sum1(3)() === 4", sum1(3)()).toBe(4)
expect("sum(1)(2)(3)() === 6", sum(1)(2)(3)()).toBe(6)
expect("sum(5)(-1)(2)() === 6", sum(5)(-1)(2)()).toBe(6)
expect("sum(1)(2)(4) == 7 -> true", sum(1)(2)(4) == 7).toBe(true)
expect("sum(1)(2)(4) === 7 -> false", sum(1)(2)(4) === 7).toBe(false)
My appreciation for any article, idea for solving the problem.
It's hard to point out what specifically you should change in you answer to make it work. When I look at the question at hand my mind immediately jumps to a recursive function that uses variable/parameter scoping to store the values.
const sum1 = sum(1)
console.log(sum1(2)()) // return 3
console.log(sum1(3)()) // return 4
// call directly without assigning to a variable
console.log(sum(1)(2)(3)()) // return 6
console.log(sum(5)(-1)(2)()) // return 6
console.log(sum(1)(2)(4) == 7) // true
console.log(sum(1)(2)(4) === 7) // false
function sum(a) {
if (!arguments.length) return;
function addA(b) {
if (!arguments.length) return a;
return sum(a + b);
};
Object.defineProperty(addA, "valueOf", {
enumerable: false,
configurable: true,
writable: true,
value() { return a },
});
return addA;
}
In the answer above !arguments.length in sumA is used to check if parameters are passed. If no parameters are passed a is returned, which holds the final sum value.
If there there is a parameter present sum(a + b) is returned which in turn returns a new addA function. This new function has it's a argument updated to hold the new value.
After creating the function sumA we give it a custom valueOf method that returns the current sum, this is used for type coercion. This is needed to let sum(1)(2)(4) == 7 evaluate properly. I've added this property as a non-enumerable property using Object.defineProperty(), but it can be simplified if you don't mind valueOf being enumerable.
To use an enumerable property change:
Object.defineProperty(addA, "valueOf", {
enumerable: false,
configurable: true,
writable: true,
value() { return a },
});
Into:
addA.valueOf = () => a;
const sum1 = sum(1)
console.log(sum1(2)()) // return 3
console.log(sum1(3)()) // return 4
// call directly without assigning to a variable
console.log(sum(1)(2)(3)()) // return 6
console.log(sum(5)(-1)(2)()) // return 6
console.log(sum(1)(2)(4) == 7) // true
console.log(sum(1)(2)(4) === 7) // false
function sum(a) {
if (!arguments.length) return;
function addA(b) {
if (!arguments.length) return a;
return sum(a + b);
};
addA.valueOf = () => a;
return addA;
}
Note that a function can be treated as a normal JavaScript object and can be assigned properties like valueOf, or any other property for that matter.

How to get Functions output and re-use within IF/else Statement

I have function at the bottom of my script which counts for how many tools were used.
Then based on how many tools were used I want to perform different actions.
I can easily check the output of the Function but I struggle to put it into If statement.
How to get Functions output and re-use it within IF Statement?
var HowManyTools = HowManyTools1();
if (HowManyTools <= 2) {
Category13();
} else if (HowManyTools >= 6) {
Category14();
} else if (HowManyTools > 2) {
Category12();
}
function HowManyTools1() {
//returns value between 1-9
}
Update: I've added if to the last else. It executes the Category13();. Without if all previous statements were simply false so it went straight to the last statement with Category12();
I can output into Category13/ Category12. But not the Category14.
It seems like my function can't get defined, as soon as I put it within a variable, and if I try to alert(HowManyTools) I simply get undefined Error.
Tried a few examples from here but to no avail
This variant should demonstrate that every one of your Category functions will run if its if-condition is met.
I pass HowManyTools to each of those functions for demonstration purposes.
for (var i = 0; i < 20; i++) {
test();
}
function test () {
var HowManyTools = HowManyTools1();
if (HowManyTools <= 2) {
Category13(HowManyTools);
} else if (HowManyTools >= 6) {
Category14(HowManyTools);
} else if (HowManyTools > 2) {
Category12(HowManyTools);
}
}
function HowManyTools1() {
return Math.floor(Math.random() * 9 + 1);
}
function Category12(val) {
console.log(`Category 12: value = ${val}`);
}
function Category13(val) {
console.log(`Category 13: value = ${val}`);
}
function Category14(val) {
console.log(`Category 14: value = ${val}`);
}

Reflection/Introspection of JavaScript Modules

Assume I have:
// test.js
function myFunc(a,b,c) {
return "Test";
}
module.exports.myFunc = myFunc;
How can I dynamically find out that test.js has a function myFunc which takes 3 parameters, so:
x = require('test.js')
if ( x has function defined myFunc ) {
if ( function myFunc in x has 3 arguments) {
"OK"
} else { "Expect 3 params"}
} else {
"test.js does not expose myFunc" }
Is this possible using reflection/introspection?
Thanks
This isn't specific to modules. Function arity can be determined with length property in JavaScript, myFunc.length === 3.
Relying on length in production is contradictory practice that often designates code smell. In tests, expected length behaviour may be undesirable.
Not too good:
function myFunc(...args) {
const [a,b,c] = args;
}
myFunc.length === 0;
Not good at all:
function myFunc(a, b = 1, c = 2) {}
myFunc.length === 1;
If myFunc.length is expected to be used in unit tests, it's recommended to skip this assertion and focus on function behaviour instead.

Dynamic if statement in JS

I have a function that looks through arrays and returns ether true or false and will change a global variable to the number that it found if it was above 0. I want to have a if statement that changes so if it is that number it'll call a different function based on that number without having multiple if statements. So something like
if(left == true){
for(i=1;i<8;i++){
if(leftnumber == i){
//function based on i
}
}
}
You can use an object to lookup a function based on the number.
// object that stores functions based on "leftnumber"
var fnTable = { };
// when "leftnumber" is 6, this function will be called
fnTable[ 6 ] = function() { ... };
// ... for loop stuff
// attempt to find the function for the value at i
var lookup = fnTable[ i ];
// if it exists, call it
if (lookup)
lookup( );
Something like this?
function myfunction(number){
//do stuff
}
if(left == true){
for(i=1;i<8;i++){
if(leftnumber == i){
myfunction(i);
}
}
}

What is the best way to have a function toggle between two different processes?

I have a function that I want it execute alternating processes every time it's triggered. Any help on how I would achieve this would be great.
function onoff(){
statusOn process /*or if on*/ statusOff process
}
One interesting aspect of JavaScript is that functions are first-class objects, meaning they can have custom properties:
function onoff() {
onoff.enabled = !onoff.enabled;
if(onoff.enabled) {
alert('on');
} else {
alert('off');
}
}
For this to work, your function should have a name. If your function is anonymous (unnamed), you can try to use arguments.callee to access it, but that is deprecated in the new ES5 standard and not possible when using its strict mode.
With the use of closures, you can define a static variable that is only accessible by the function itself:
var toggle = (function()
{
var state = true;
return function()
{
if(state)
alert("A");
else
alert("B");
state = !state;
};
})();
Now you can repeatedly invoke toggle(), and it would alternate between "A" and "B". The state variable is unaccessible from the outside, so you don't pollute the global variable scope.
Use closures. In addition to closures, this method demonstrates arbitrary arguments and arbitrary numbers of functions to cycle through:
Function cycler
function cycle() {
var toCall = arguments;
var which = 0;
return function() {
var R = toCall[which].apply(this, arguments);
which = (which+1) % toCall.length; // see NOTE
return R;
}
}
Demo:
function sum(a,b) {return a+b}
function prod(a,b) {return a*b}
function pow(a,b) {return Math.pow(a,b)}
function negate(x) {return -x;}
var f = cycle(sum, prod, pow, negate);
console.log(f(2,10)); // 12
console.log(f(2,10)); // 20
console.log(f(2,10)); // 1024
console.log(f(2)); // -2
// repeat!
console.log(f(2,10)); // 12
console.log(f(2,10)); // 20
console.log(f(2,10)); // 1024
console.log(f(2)); // -2
Arbitrary cycler
Alternatively if you do not wish to assume all cycled things are functions, you can use this pattern. In some ways it is more elegant; in some ways it is less elegant.
function cycle() {
var list = arguments;
var which = 0;
return function() {
var R = list[which];
which = (which+1) % toCall.length; // see NOTE
return R;
}
}
Demo:
var cycler = cycle(function(x){return x}, 4, function(a,b){return a+b});
cycler()(1); // 1
cycler(); // 4
cycler()(1,5); // 6
// repeat!
cycler()(1); // 1
cycler(); // 4
cycler()(1,5); // 6
NOTE: Because javascript thinks 10000000000000001%2 is 0 (i.e. that this number is even), this function must be three codelines longer than necessary, or else you will only be able to call this function 10 quadrillion times before it gives an incorrect answer. You are unlikely to reach this limit in a single browsing session... but who knows
If I'm understanding what you want, this may be what you're looking for:
var AlternateFunctions = function() {
var one = function() {
// do stuff...
current = two;
}, two = function() {
// do stuff...
current = one;
}, current = one;
return function() {
current();
}
}();
Then calling AlternateFunctions(); will cycle between one() and two()
There are a couple of good answers already posted, but I'm wondering what you're trying to achieve. If you're keeping track of some DOM element's state, instead of having state saved within the function, you should check the state of the element so that the function isn't operating in a vacuum (and possibly not doing what you expect). You can check some attribute, e.g., class:
function onoff(obj){
if(obj.className === 'on') {
obj.className = 'off';
}else{
obj.className = 'on';
}
}
var last=0;
function toggle() {
if(last) {
last=0;
// do process 2
}
else {
last=1;
// do process 1
}
}
See jsfiddle demo
var status=true;
function onOff(el){
/*
* toggle
*/
status = (status ? false : true);
status
? el.html('on')
: el.html('off');
}

Categories

Resources