Is it possible to dynamically build a function based off another functions parameters?
For example:
Base Function:
const someFunction = (functionName, functionParams) => {
// Function Built here
};
someFunction("colorFunction", ["red", true]);
I'd like it to build something similar to this: I'd need to deconstruct the Array into individual params, but I'm not sure how simple that is? And I have no idea how I'd use the first String to call the function name?
functionName(...functionParams);
Which in my head would sort of work like this:
const colorFunction = (color, bool) => {
console.log("Colour: " + color);
console.log("Bool: " + bool);
};
Bit confused by this - I feel like I'm not a million miles away, but I'm not certain! Any help would be great, thanks!!
Edit - Why?
I have a react component with a click event that fires off a redux action. Ideally this action would fire some stuff over to my reducer, and asynchronously call this "dynamic" function. I can do this with a load of if/elses, but I don't think that's a very clean way of achieving this, if building a function this way is possible.
First you need to determine where the functions you want to call dynamically are stored. If they are global functions then you can call them using window:
const someFunction = (functionName, functionParams) => {
window[functionName]();
};
If they are methods of an object, then you can do something similar using the object:
const someFunction = (functionName, functionParams) => {
myObject[functionName]();
};
As for how to pass the arguments, you have a couple options here. If you are running a recent version of JS, or using polyfills, then you can indeed use the spread operator:
const someFunction = (functionName, functionParams) => {
window[functionName](...functionParams);
};
Otherwise you can always rely on the apply method:
const someFunction = (functionName, functionParams) => {
window[functionName].apply(null, functionParams);
};
The first argument in the apply method is the context you wish to pass to your function, in your case it doesn't seem necessary, hence the null value.
Edit: corrected bind with apply as mentionned by Bergi
What you are looking for is Function#bind in order to make a thunk - basically a function that takes no parameters and it's used for delayed computation.
Using .bind you can do a partial application on a function. In your case, you would just apply all arguments and only leave the execution step at the end:
//your function
const colorFunction = (color, bool) => {
console.log("Colour: " + color);
console.log("Bool: " + bool);
};
//partially apply all argument to it
const thunk = colorFunction.bind(null, "red", true);
//this can now be passed around and executed at a later point
setTimeout(thunk, 3000);
console.log("wait 3 seconds");
Since functions are first class members in JavaScript, you can pass any function this way. If you really need a function that turns others into thunks then you can very easily do that:
const toThunk = (func, args) => func.bind(null, ...args);
Which is your someFunction but with just the name and parameters re-named for a bit of clarity.
Related
I am creating an observable like so:
return new Observable(sub => {
const {next, complete, error} = sub;
this.AuthHttp.get(`http://192.168.1.100:3000/api/users/${id}`)
.subscribe(res => {
let user = res.json();
next(user);
complete();
}, e => {
error(e.json());
});
})
Yet it nothing is happening in my front end when next() is expected to be called. If I make a minor change to the code so that sub.next() is called instead, everything works as expected. This indicates the underlying code is not flawed, just the way I am making a reference to next.
I have seen this form of destructuring used with the Observer class before (in an example online), so what am I doing wrong here?
Because the next, error and complete methods are object methods that must be called on an object instance.
When you use destructuring to obtain the functions and later call those functions, the calls are without context.
You cannot do what you've attempted for the same reason that this will not work:
const { toString } = new Date();
console.log(toString());
For more information, see this issue.
I am currently looking into utilizing mostly pure functions in my code. I realize the benefits of this. However, I'm wondering what the best practice is when updating a state variable, calling methods defined within a module, and how to handle window functions.
Using the example below, let's say I have a module, MyModule.
The MyModule.calculate function is pure, so no worries there.
The MyModule.trackSomething function however is updating the MyModule.count to keep track of it for use in the event handler, used in MyModule.assignEventHandlers function. This is not pure because it is using an outside reference to a variable. Even if I refactor to make count an object and pass it in as a parameter to MyModule.trackSomething, I'd still be altering the value through reference, making it impure.
In the MyModule.assignEventHandlers function, I'm using global window object functions. This makes it impure because I'm referencing outside functions. Should the window object be passed by reference when calling functions it has?
In the MyModule.init function, I'm calling the MyModule.assignEventHandlers function. I guess this makes it impure as well since MyModule.assignEventHandlers is an outside reference.
So my question is: What is the best way to handle the last 3 bullet points?
Any advice is much appreciated. Thanks!
const MyModule = {
calculate(a, b) {
return a + b;
},
count: 0,
trackSomething() {
MyModule.count += 1;
},
assignEventHandlers() {
// assign event handlers to some DOM elements
window.document.getElementById('my-ele').addEventListener('click', () => {
window.alert(MyModule.count);
MyModule.trackSomething(MyModule.count);
});
},
init() {
MyModule.assignEventHandlers();
}
};
I think when we came out with a solution, instead of just focus on pure and impure function, it's better to focus on practicability as well. It's okay to have impure function.
Here is another version of the implementation using RxJs - a reactive js lib. Also using ES6 class instead of module. Take a look at action and action2. Both produce same result in different ways.
In my opinion, action is good enough. Don't need to make everything super pure.
class MyClass {
constructor(elementId) {
this.ele = document.getElementById(elementId);
this.click$ = Rx.Observable.fromEvent(this.ele, 'click');
this.count = new Rx.BehaviorSubject(0);
}
calculate(a, b) {
return a + b;
}
action() {
window.alert(this.count.getValue());
const nextVal = this.calculate(this.count.getValue(), 1);
this.count.next(nextVal);
}
action2(log, subject, method) {
log(subject.getValue());
const nextVal = method(subject.getValue(), 1);
subject.next(nextVal);
}
}
const a = new MyClass('my-ele1');
a.click$.subscribe(() => a.action2(window.alert, a.count, a.calculate));
const b = new MyClass('my-ele2');
b.click$.subscribe(() => b.action());
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
<button type="button" id="my-ele1">me1</button>
<br>
<button type="button" id="my-ele2">me2</button>
Let me start by saying this is more of a curiosity question because, as you will see, I was able to achieve the desired functionality.
However, given that javascript is a super flexible language, I would like to see what other devs might think about this problem:
I have an instance of a class which is returned from a vendor function:
const connection = vendorDatabaseLib.createConnection();
Now, I would like to create a decorator which will add functionality to the connection class, for example, reconnection logic.
Lets call it PersistentConnection. Apart from my added custom functions I would like an instance of PersistentConnection to forward all function calls to the original Connection instance. And in some functions override the behaviour.
I could of course implement all Connection's functions explicitly and forward them to the inner object but there might be lots of these functions, so I quickly discarded this idea.
So here are my ideas of how to achieve this:
Monkey patching 🐒, Instead of a decorator I can create a PersistentConnection class which inherits from the vendor Connection and then patch the vendor vendorDatabaseLib.createConnection function to return PersistentConnection with all my desired added functionality. Tempting, but bad.
Create a decorator which iterates over the Connection functions and creates forwards dynamically, something like:
class PersistentConnection{
constructor(connection){
this._connection = connection;
// Iterate through all functions
for (prop in this._connection){
if(typeof(this._connection[prop]) === 'function'){
// Create functions dynamically for each forward
this[prop] = (...args) => {
this._connection[prop](...args);
}
}
}
}
// This is the added logic
reconnect(){
// Custom logic
}
}
Set the Connection instance to be a the prototype of PersistentConnection's instance:
function persistenChannel(channel){
const persistentChannel = {};
Object.setPrototypeOf(persistentChannel, channel);
persistentChannel.reconnect = () => {
// custom logic
}
}
This is the most "automatic" way I could think of.. But it just down right ugly, and the custom functions need to be declared each time an instance is created.
I still feel like I'm missing something, something like Ruby's magical method_missing (or pythons __getattr__) function which is called just before a method is missing exception is thrown and lets you define "safety net" logic (like delegating all calls to the inner _connection object.
Is there a better way to achieve this functionality?
Thanks a lot [=
Lets start from what we have. In any case, most of the functionaliy will be performed by vendor object. We do not know details realization so we can't rely that this object has no state. This mean, that in any case we need new connection object for the new persistentConnection. This can be achieved with proxy object
Lets try to do this:
function Connection() {
this.connect = () => console.log('connected by Connection class');
this.disconnect = () => console.log('disconnected by Connection class');
}
function persistantConnectionFactory() {
function PersistentConnection() {
this.checkConnection = () => console.log('no connection');
}
const instance = new PersistentConnection();
const proxy = new Proxy(instance, {
get: function (target, name) {
if (!(name in target)) {
console.log('adding new prototype')
Object.setPrototypeOf(instance, new Connection())
}
return target[name];
}
});
return proxy;
}
var c = persistantConnectionFactory();
c.checkConnection();
c.connect();
Does this solution good? I think - not. Without very good reasons this adds complexity without any value. Prototype should be enough.
I need to feed a pipe() handler function a bunch of function names so it can execute them in order, waiting for completion of each as it goes. This is great when those functions don't need parameters passing, but when parameters are needed I can't figure out how to pass them without the function going ahead and invoking itself (caused by the brackets).
For example, this is what I typically pass:
pipeHandler([function1, function2]);
It'll then invoke function1() and function2() before the promise is completed.
Where it gets difficult is when I want to do something like thiss:
pipeHandler([function1('value'), function2]);
That causes function1() to invoke immediately, completely bypassing the promise mechanism.
In case it helps, this is the handler function:
function pipeHandler(requiredFunctions) {
//Execute first required function
var executeFunctions = requiredFunctions[0]();
//Execute each subsequent required function using pipe()
for ( var index = 1; index < requiredFunctions.length; index++ ) {
executeFunctions = executeFunctions.pipe(requiredFunctions[index]);
}
//Execute allDone() using pipe()
executeFunctions = executeFunctions.pipe(allDone);
}
Hope somebody has an idea!
Why not
pipeHandler([function() { function1('value'); }, function2]);
?
This is where anonymous functions shine. If you spend some time working in Javascript, you'll probably encounter the same problem when using setTimeOut at some point.
This can be done concisely using bind. Syntax:
pipeHandler([function1.bind(scope, 'value')]);
Bind returns a partial function application, which is a new function in scope scope, with the fixed first parameter 'value'. It'll work with any number of arguments.
You can use an anonymous function, which can invoke the function1
pipeHandler([function () {;
function1('value')
}, function2]);
if you wanna pass parameters without invoking function you may do it like so :
function add (a, b) {
return a + b;
}
// Outputs: 3
console.log(add(1, 2));
// Outputs: function
console.log(add.bind(this, 1, 2));
and this will return a function
function () { [native code] }
if you wanna invoke it
// this will return 3
console.log(add.bind(this, 1, 2)());
What you're probably looking for is called 'Partial application.'
Depending on which browsers you need to support you may be able to simply use bind.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Partial_Functions
As far as I can tell from reading the question, there is no asynchronicity, just a regular single-threaded sequence of function calls, with the possibility of passing parameters at each call.
If so then you want to use jQuery.Callbacks. Your scenario is precisely what jQuery.Callbacks are for. The documentation says :
The jQuery.Callbacks() function, introduced in version 1.7, returns a
multi-purpose object that provides a powerful way to manage callback
lists. It supports adding, removing, firing, and disabling callbacks.
Having read the documentation for jQuery.Callbacks, it's probably still not obvious how to pass parameters to functions in the list.
The simplest option is to fire the list with an object that can be used by the functions in the list :
function myFunction1(obj) {
console.log(obj.myProperty1);
}
function myFunction2(obj) {
console.log([obj.myProperty1, obj.myProperty2].join());
}
var callbacks = $.Callbacks();
callbacks.add(myFunction1);
callbacks.add(myFunction2);
callbacks.fire({
myProperty1: 'X',
myProperty2: 'Y'
});
A more sophiisicated approach allows you :
to specify parameter(s) for each function as it is added to the list, and
to specify a context for all functions in the list
thus giving you two mechanisms for passing data to the functions and the freedom to specify that data in either a .add() statement or a .fire() statement, or both.
For this, you need the following utility function :
function makeClosure(fn) {
var args = Array.prototype.slice.call(arguments, 1);//seriously clever line - thank you John Resig
return function (context) {
fn.apply(context, args);
}
}
which can be used as follows :
function f1() {
console.log(this.myProperty));
}
function f2(value1, value2) {
console.log(value1 + ', ' + value2);
}
function f3(value1, value2) {
//note the use of `this` as a reference to the context.
console.log(value1 + ', ' + value2 + ', ' + this.myProperty);
}
var callbacks = $.Callbacks();
callbacks.add(makeClosure(f1, 'A1'));
callbacks.add(makeClosure(f2, 'B1', 'B2'));
callbacks.add(makeClosure(f3, 'C1', 'C2'));
callbacks.fire({
myProperty: 'Z'
});
DEMO
jQuery's $.proxy(function, context, value) is particularly helpful in this case since it:
Takes a function and returns a new one that will always have a particular context.
Therefore, not only you can change the context of the function being invoked (you can provide an object instead of this), but you can also pass as many arguments/parameters values as the function receives without invoking it directly:
function fun_w_param(v) {console.info("I'm #1, here's my value: " + v)}
function fun_no_param() {console.info("I'm #2")}
function pipeHandler(f1, f2) {
f2();
console.warn("Handling function1 with a second delay");
setTimeout(function(){f1()}, 1000);
}
// add your value below as a proxy's argument
pipeHandler(
$.proxy(fun_w_param, this, '!!!PROXY!!!'),
fun_no_param
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Running the above will delay "function1" execution and it will display the value that you provide into the proxy's parameter.
Using arrow methods you can simply do this
pipeHandler([() => function1('value'), function2]
I want to write my own function in JavaScript which takes a callback method as a parameter and executes it after the completion, I don't know how to invoke a method in my method which is passed as an argument. Like Reflection.
example code
function myfunction(param1, callbackfunction)
{
//do processing here
//how to invoke callbackfunction at this point?
}
//this is the function call to myfunction
myfunction("hello", function(){
//call back method implementation here
});
You can just call it as a normal function:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction();
}
The only extra thing is to mention context. If you want to be able to use the this keyword within your callback, you'll have to assign it. This is frequently desirable behaviour. For instance:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction.call(param1);
}
In the callback, you can now access param1 as this. See Function.call.
I too came into same scenario where I have to call the function sent as parameter to another function.
I Tried
mainfunction('callThisFunction');
First Approach
function mainFuntion(functionName)
{
functionName();
}
But ends up in errors. So I tried
Second Approach
functionName.call().
Still no use. So I tried
Third Approach
this[functionName]();
which worked like a champ. So This is to just add one more way of calling. May be there may be problem with my First and Second approaches, but instead googling more and spending time I went for Third Approach.
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction(); // or if you want scoped call, callbackfunction.call(scope)
}
object[functionName]();
object: refers to the name of the object.
functionName: is a variable whose value we will use to call a function.
by putting the variable used to refer to the function name inside the [] and the () outside the bracket we can dynamically call the object's function using the variable. Dot notation does not work because it thinks that 'functionName' is the actual name of the function and not the value that 'functionName' holds. This drove me crazy for a little bit, until I came across this site. I am glad stackoverflow.com exists <3
All the examples here seem to show how to declare it, but not how to use it. I think that's also why #Kiran had so many issues.
The trick is to declare the function which uses a callback:
function doThisFirst(someParameter, myCallbackFunction) {
// Do stuff first
alert('Doing stuff...');
// Now call the function passed in
myCallbackFunction(someParameter);
}
The someParameter bit can be omitted if not required.
You can then use the callback as follows:
doThisFirst(1, myOtherFunction1);
doThisFirst(2, myOtherFunction2);
function myOtherFunction1(inputParam) {
alert('myOtherFunction1: ' + inputParam);
}
function myOtherFunction2(inputParam) {
alert('myOtherFunction2: ' + inputParam);
}
Note how the callback function is passed in and declared without quotes or brackets.
If you use doThisFirst(1, 'myOtherFunction1'); it will fail.
If you use doThisFirst(1, myOtherFunction3()); (I know there's no parameter input in this case) then it will call myOtherFunction3 first so you get unintended side effects.
Another way is to declare your function as anonymous function and save it in a variable:
var aFunction = function () {
};
After that you can pass aFunction as argument myfunction and call it normally.
function myfunction(callbackfunction) {
callbackfunction();
}
myfunction(aFunction);
However, as other answers have pointed out, is not necessary, since you can directly use the function name. I will keep the answer as is, because of the discussion that follows in the comments.
I will do something like this
var callbackfunction = function(param1, param2){
console.log(param1 + ' ' + param2)
}
myfunction = function(_function, _params){
_function(_params['firstParam'], _params['secondParam']);
}
Into the main code block, It is possible pass parameters
myfunction(callbackfunction, {firstParam: 'hello', secondParam: 'good bye'});
callbackfunction = () => {}
callbackfunction2(){
}
function myfunction1(callbackfunction) {
callbackfunction();
}
//Exe
myfunction1(callbackfunction);
myfunction1(callbackfunction2.bind(this));
Super basic implementation for my use case based on some excellent answers and resources above:
/** Returns the name of type member in a type-safe manner. **(UNTESTED)** e.g.:
*
* ```typescript
* nameof<Apple>(apple => apple.colour); // Returns 'colour'
* nameof<Apple>(x => x.colour); // Returns 'colour'
* ```
*/
export function nameof<T>(func?: (obj: T) => any): string {
const lambda = ' => ';
const funcStr = func.toString();
const indexOfLambda = funcStr.indexOf(lambda);
const member = funcStr.replace(funcStr.substring(0, indexOfLambda) + '.', '').replace(funcStr.substring(0, indexOfLambda) + lambda, '');
return member;
}