js - pass extra param to callback function - javascript

I'm trying to pass an extra param to a 3rd callback function (its not my own callback).
const selectedItems = dt.rows({ selected: true });
const selectedIndexes = selectedItems.indexes();
const selectedData = selectedItems.data();
let data_object = [];
$.each(selectedData, (i, o) => {
data_object.push(o['PackageName']);
});
window.bridge.deleteApps(data_object, (success_list, selectedIndexes) => {
console.log("test"); // selectedIndexes -> undefined
});
Background: It's a function that comes with Qt that triggers a python method (pyqt), the first param is passed to python the second param is a callback function with the return from the python method (success_list) but i need selectedIndexes too.
When I do
window.bridge.deleteApps(data_object, (success_list, abc=selectedIndexes) => {
console.log("test"); // abc + selectedIndexes is available
});
I'm sorry that I've no working snippet for you to test but I did some researchs about callbacks and actually don't understand it, so I'm not able to reproduce this case.

I think part of your confusion is how callbacks are handled. Basically it's up to the window.bridge.deleteApps function to pass parameters to the callback you provide. So unless you're the author of that function, there's not a good way to have it pass you additional parameters. However, in the above example you should have access to selectedIndexes because you've declared it with const and it will be accessible from your callback.
So you should be able to have this code:
window.bridge.deleteApps(data_object, (success_list) => {
console.log(selectedIndexes); // Should be available because you've declared it in a higher scope
console.log(success_list); // Gets passed by the .deleteApss function
});

Related

Function returning a function doesn’t throw an error despite the argument being undefined

I saw in one tutorial this code snippet:
const myFunction = () => {
return function (caller) {
caller(firstFuctnion());
caller(secondFunction());
};
};
Could you please tell me how it works once I call it like:
myFunction()
How come that I don’t get an error when the caller argument is actually not defined?
On the other hand, if I omit it and write the code like this:
const myFunction = () => {
return function () {
firstFuctnion();
secondFunction();
};
};
those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
For those of you who might want to see the whole functioning code:
const redux = require("redux");
const thunkMiddleware = require("redux-thunk").default;
const axios = require("axios");
const createStore = redux.createStore;
const applyMiddleware = redux.applyMiddleware;
const initialState = {
loading: false,
users: [],
error: "",
};
const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
const fetchUsersRequest = () => {
return {
type: FETCH_USERS_REQUEST,
};
};
const fetchUsersSuccess = (users) => {
return {
type: FETCH_USERS_SUCCESS,
payload: users,
};
};
const fetchUsersFailure = (error) => {
return {
type: FETCH_USERS_FAILURE,
payload: error,
};
};
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
const reducer = (state = initialState, action) => {
console.log(action.type);
switch (action.type) {
case FETCH_USERS_REQUEST:
return {
...state,
loading: true,
};
case FETCH_USERS_SUCCESS:
return {
loading: false,
users: action.payload,
error: "",
};
case FETCH_USERS_FAILURE:
return {
loading: false,
users: [],
error: action.payload,
};
}
};
const store = createStore(reducer, applyMiddleware(thunkMiddleware));
store.subscribe(() => {
console.log(store.getState());
});
store.dispatch(fetchUsers());
I don't get this part. What that dispatch actually does. It is nowhere passed as an argument and it is not defined anywhere what it is. Is it function? I could write whatever there instead.
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
Let’s consider a simplified version of this code.
Before you added some important context to your question (the fact that myFunction() is actually being used, and how it’s used), I wasn’t quite sure where your confusion was, so this answer starts with a general explanation of callbacks, higher-order functions, and currying.
First, let’s turn the function into an arrow function, so the code is more straight-forward to read.
There are differences between them, but let’s ignore them for now.
Let’s also rename myFunction to outer, so we know which function we’re talking about.
const outer = () => {
return (caller) => {
caller(something);
};
};
outer is a function.
outer() is also a function; that means, the return value of the function outer is, itself, a function.
Since outer is a function that returns a function, this makes outer a higher-order function (HOF) (according to one of the two definitions of HOFs)1.
To be explicit, you can reference the returned function by using another variable:
const inner = outer();
How come that I don’t get an error when the caller argument is actually not defined?
That’s a strange question to ask; when outer() is called, it doesn’t touch on caller yet.
Only calling inner does.
Ask yourself this: why do you not get an error for a and b not being defined here?2
const sum = (a, b) => a + b;
sum;
That’s right: sum isn’t even called!
Just like outer() isn’t even called.
Even one step further, this won’t throw an error even if somethingUndefined isn’t defined anywhere and cannot be set anywhere.
(But you will get linter warnings.)
const someFunction = () => somethingUndefined;
someFunction;
Why do you not get an error here, in this common example of HOFs, despite b not being defined at the point where add(5) is assigned to addFive?
const add = (a) => {
return (b) => a + b;
};
// Or more simply:
// const add = (a) => (b) => a + b;
const addFive = add(5);
console.log(addFive(3)); // Pints 8.
Because the function that needs b, i.e. addFive, has not been called yet.
If you want to force an error due to caller not being defined, you’d have to call the function that actually needs caller defined. The function in question is outer()! You call it, like any other function, with (): outer()(). Now you get a TypeError because caller isn’t a function.
This “double call” is called currying.
The code can also be rewritten like this.
The only difference is that inner is now also accessible in the outer scope where outer is.
See What is the scope of variables in JavaScript?.
const inner = (caller) => {
caller(something);
};
const outer = () => inner;
inner takes the role of the returned function (outer()).
It takes a function as an argument and calls it with something as an argument.
outer is just a function that returns the function inner and nothing else.
It does not call it, it doesn’t touch on caller, it has nothing to do with something.
outer() and inner are identical.
On the other hand, if I omit it and write the code [without caller], those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
First, let’s fix the semantics: firstFuction() and secondFunction() are function calls.
Whether they are functions or not, depends on what firstFuction and secondFunction return.
firstFuction and secondFunction are functions (at least the code implies that they are).
More specifically, consider alert:
alert is a function; you can call it like alert().
alert() is not a function; you cannot call it like alert()().
caller is a callback function.
If you omit caller from the code, then myFunction()() would be the proper call that doesn’t throw an error and simply calls firstFuction and secondFunction.
But the point of the callback is to pass the results of firstFuction and secondFunction to the function caller.
You have to provide that function yourself, e.g. the alert function.
myFunction()(alert) calls the inner function, passing alert to it.
The inner function calls firstFuction and secondFunction and passes their results to the caller, which we specified to be alert.
Could you please tell me how it works once I call it like myFunction()?
Quite simply, nothing happens here.
myFunction returns a function, and that’s it; that function isn’t used further, so it is discarded.
There is a key aspect of higher-order functions that isn’t demonstrated in this code: encapsulating values.
Consider this code:
const add = (a) => {
let count = 0;
return (b) => {
++count;
console.log(`The function to add ${a} to something else has been called ${count} time(s).`);
return a + b
};
};
add and b work similarly to myFunction and caller from before, but now, the outer function also needs an argument, so add() won’t help.
add(5) calls the add function and sets argument a to 5.
Further, add(5)(3) calls the inner, returned function, sets b to 3 and returns 8.
But there’s also some state inside add in the form of a variable called count.
const addFive = add(5);
console.log(addFive(3)); // Prints 8.
// But also logs: "The function to add 5 to something else has been called 1 time(s)."
console.log(addFive(10)); // Prints 15.
// But also logs: "The function to add 5 to something else has been called 2 time(s)."
count is only accessible inside outer (including any function inside of it); it is “encapsulated”.
This is a common way to hide some state that should only be accessible inside a specific function.
a is actually also encapsulated inside add(…); a and count have the same scope and aren’t that different from each other, just that a can be set as an argument when calling add whereas count cannot.
You’ve then added more context, where the call looks more like this:
someOtherFunction(myFunction())
This is different from the situation before where you just wrote the call like myFunction().
Now, the result is not discarded, as it is fed into someOtherFunction (in the original code: store.dispatch).
[caller] is nowhere passed as an argument and it is not defined anywhere.
But now it is the job of someOtherFunction to call myFunction() with the appropriate callback function as an argument.
Now, you don’t pass the function yourself; instead, someOtherFunction does it for you.
Compare this to Where do the parameters in a JavaScript callback function come from?.
If you go back to the sum example function from earlier, then either you pass the arguments yourself:
sum(1, 2);
or some library or framework does it for you:
// Library code
const doTheRightThing = (callback) => callback(1, 2);
// Your code
doTheRightThing(sum);
or a built-in (or host-defined) function does it for you:
[ 1, 2, 3 ].reduce(sum, 0);
It doesn’t matter where these parameters come from or where the function is called from.
But it is called, and it is called with the right arguments somewhere.
1: The two definitions of a higher-order function are
a function that returns a function, or
a function that takes another function as an argument.
outer fits the first definition.
outer() (independently and coincidentally) fits the second definition.
2: Okay, granted, sum() would also not throw an error, but a and b would, nonetheless, be undefined, each. undefined + undefined has semantics that don’t result in an error, but hopefully you get the point: in your original code, myFunction()() would throw an error only because undefined(firstFunction()) isn’t possible. The culprit is the same: caller is undefined.
Functions are treated like any other values, meaning they can be returned from functions.
Calling myFunction will simply return the inner function, which will require a parameter caller to be passed to it when it itself is called.
The inner function will remember any arguments that were passed to it's enclosing function.
An example I use to understand this concept is that of a "multiplier factory" function
const answer = function() {
console.log("The answer is: ");
}
const multiplier = function(factor) {
return function(n){
answer();
console.log( n * factor);
};
}
const twice = multiplier(2);
const triple = multiplier(3);
twice(4); // The answer is: 8
triple(5); // The answer is: 15
In the code above twice and triple are essentially the following
const twice = function(n) {
console.log("The answer is: ");
console.log(n * 2);
}
const triple = function(n) {
console.log("The answer is: ");
console.log(n * 3);
}
twice(4); // The answer is: 8
triple(5); // The answer is: 15
To understand more about these concepts, I suggest reading up on "Higher Order Functions" and "Closures" in Javascript
I think you haven't printed the whole snipet. because, there is no definition to firstFunction() and secondFunction() inside myFunction().
to answer your question, if you want to call the function defined in myFunction(), you need to assign the value to a new variable as it is returning the function. then simple make the function call.
const myFunctionResult = myFunction();
myFunctionResult(someOtherCallerFunction);
but note this will throw an error for the reason mentioned above.

How does work function returning another function that taking another argument?

I have a function from Dan Abramov`s redux course. It takes store but returning a function taking action as an argument. I know clojures but in function we didnt excute last function. addLoggingToDispatch function doesn't have action argument how does that function works?
const addLoggingToDispatch = (store) => {
const rawDispatch = store.dispatch;
return (action) => {
console.group(action.type);
console.log('%c prev state', 'color: gray', store.getState());
console.log('%c action', 'color: blue', action);
const returnValue = rawDispatch(action);
console.log('%c next state', 'color: green', store.getState());
console.groupEnd(action.type);
return returnValue;
};
};
It looks like this function is intended to replace or wrap the dispatch method that comes with your store. The dispatch method takes an action as an argument, so it has the same signature as your return function. So wherever you actually create the store, do something like this:
const store = createStore()
store.dispatch = addLoggingToStore(store)
You might clarify this post by showing us where you actually are using addLoggingToStore. But if I understand correctly this purpose of this function is to bake in logging functionality without creating any sort of additional logging middleware. Now, whenever you call dispatch(someAction), it will run your function instead of the default provided by the redux store.
The function that addLoggingToDispatch returns closes over the store parameter. Then, when that function is called, it gets passed an argument for action. So when that function that's returned is running, it has access to action (because that's one of its parameters) and store (because it closes over addLoggingToDispatch's parameter).
When a function is created inside another function and the inner function continues to exist after the outer function returns (because the outer function returns it, or it's been added to a list of functions like an event handler list, etc.), the inner function has an enduring link to the context in which it was created (the call to the outer function) and all of the in-scope parameters/variables of that context (store, in this example).
Here's a simpler example:
function createAdderFunction(a) {
return function(b) {
return a + b;
};
}
var addFive = createAdderFunction(5);
// Now, `addFive` is a function that will add 5 to whatever you call it with
console.log(addFive(2)); // 7
console.log(addFive(37)); // 42
var addTen = createAdderFunction(10);
// And `addTen` is a function that will add 10 to whatever you call it with
console.log(addTen(15)); // 25
// `addFive` and `addTen` are separate from each other and work independently
console.log(addFive(0)); // 5
console.log(addTen(0)); // 10

JS: Rebound "this" in contextless function call

The function doSomethingElse in this example fails to execute since its this has been rebound to window or global (if in Node) due to a contextless call inside app.populateDatabase.
Is there any way to avoid this without referencing app inside every function?
loadDatabase function executes a callback according to a logic statement, if an imaginary database didn't exist, it populates it after loading, then the populateDatabase executes the callback it has been provided.
I cannot rebind the onLoaded argument to app since I don't know where it comes from, and the bind/apply/call abstraction overuse creates quite a mess.
var app = {};
app.loadDatabase = function(onLoaded) {
// If database already exists, only run a callback
var callback = onLoaded;
// If database doesn't exists, populate it, then run a callback.
if (!databaseExists) {
callback = this.populateDatabase.bind(this, onLoaded);
}
this.database = new sqlite.Database("file.db", function(error) {
if (error) { ... }
callback();
})
}
app.populateDatabase = function(onPopulated) {
// Contextless call here. <--------
onPopulated();
}
app.doSomethingElse = function() {
// this != app due to contextless call.
this.somethingElse();
}
app.run = function() {
// Load the database, then do something else.
this.loadDatabase(this.doSomethingElse);
}
app.run();
Just replace this.loadDatabase(this.doSomethingElse);
with this.loadDatabase(() => this.doSomethingElse());. This way you create a new arrow function but then doSomethingElse is called with the right this context.
You could also do .bind but I recommend the arrow function. Here with bind: this.loadDatabase(this.doSomethingElse.bind(this))
In general consider to move to promises & maybe async functions. Then do this:
this.loadDatabase().then(() => this.doSomethingElse());
or better with an async function:
await this.loadDatabase();
this.doSomethingElse();

How to prevent bind from mutating original object in node.js when using async.series?

I have the following test code:
var async = require('async');
var GROUP = 'testGroup';
var opts = {
someKey: 'hi',
};
test(opts);
function test(options) {
async.series([
doThis.bind(null, options),
doThat.bind(null, options),
], function(results) {
debugger;
});
}
function doThis(options, cb) {
options.someKey = [GROUP, options.someKey].join('.');
return cb();
}
function doThat(options, cb) {
debugger;
options.someKey = [GROUP, options.someKey].join('.');
return cb();
}
When we hit the debugger in doThat(), options.someKey already has the value someGROUP.hi, so when the function finishes we end up with options.someKey === 'someGROUP.someGroup.hi'
How do we bind such that the original object does not change? The bind is necessary because we need to pass in options to the functions that run within async.series. Otherwise, we could just invoke the functions and pass in the object as a parameter.
I'm don't think your partially applying the options parameter to your doThis(), doThat() functions is especially pertinent.
You're passing the same javascript object/literal as aparameter to two functions and and then mutate that parameter.
If you don't to mutate that object then don't. Find some other way of returning the results of your operation. doThis() and doThat() could return values instead of modifying the parameter. You could gather them up in the final callback after the series gets called.
If you just want to preserve the intital value of opts, use lodash or something to make a deep clone of opts before you pass it into test.

Reassign variables stored in closure using a callback or global function

EDIT
Let me get more to the point. I'm trying to create a psuedo promise implementation. The idea here being that I have a callback that won't be executed until an asynchronous call is received. So I'm simply queueing up all the calls to this function until the time at which it's notified that it can be executed. The queue is emptied and any further call to the function is SUPPOSED to execute immediately, but for some reason, the function is still queueing. This is because, for whatever reason, my redefinition of the runner function is not working correctly. The code below was my sleep deprived, frustrated version of every thought that went through my head. Here's the actual code:
function Promise(callback){
var queue = []
, callback = callback
, runner = function(){
queue.push({
context: this,
args: Array.prototype.slice.call(arguments, 0)
});
}
;//var
runner.exec = function(){
for(var i = 0, ilen = queue.length; i < ilen; i++){
var q = queue[i];
callback.apply(q.context, q.args);
}
runner = callback;
};
return runner;
}
test = Promise(function(){
$('<div/>').appendTo('#output').html(Array.prototype.slice.call(arguments,0).toString());
});
test(1,2);
test(3,4);
test.exec();
test(5,6);​
http://jsfiddle.net/a7gaR/
I'm banging my head against the wall with this one. I'm trying to reassign variables in a function from a call outside the function itself (ideally by passing a reassignment function as a callback). In the example I posted on jsfiddle, I made a global function that, in theory, has a reference to the variables contained within its parent function. Upon calling that external function, I expect it to reassign the values that the other function is using. It doesn't seem to work this way.
window.test = function temp() {
var val = 7,
func = function() {
return val;
};
window.change = function() {
window.test.val = 555555;
$('<div>Changing ' + val + ' to ' + window.test.val +
'</div>').appendTo($output);
val = window.test.val;
temp.val = window.test.val;
func = function() {
return 'Why isn\'t this working?';
}
}
return func();
}
var $output = $('#output');
$('<div/>').appendTo($output).html('::' + test() + '::');
window.change();
$('<div/>').appendTo($output).html('::' + test() + '::');
http://jsfiddle.net/YhyMK/
The second time you call test you're creating a new local variable called func and defining a new window.change that closes over that new variable. The changes you made to the original func by calling the original window.change are not relevant in the second call.
Also note that the following line:
window.test.val = 555555;
...does not modify/refer to the val variable in the outer function. window.test.val refers to a property named val on the test object (which happens to be a function), not any local variable.
You are trying to refer to a local variable in a function with the syntax func.varname. That won't work, that's not the way local variables work.
I finally created a function that would perform this operation. The gist for it is here: https://gist.github.com/2586972.
It works like this...
You make a call to Defer passing the callback whose functionality you'd like to delay:
var deferredCB = Defer(function(){ console.log(this,arguments) };
deferredCB will now store all of the arguments you pass allowing them to be executed at some later date:
defferedCB(1);
defferedCB(2);
Now, when you're ready to perform the operation, you simply "execute" deferredCB:
defferedCB.exec();
Which results in:
// window, 1
// window, 2
All future calls to deferredCB will be executed immediately. And now that I'm thinking about it, I'll probably do a rewrite to allow you to reset deferredCB to it's pre-executed state (storing all the arguments again).
The key to making it work was having a wrapper function. Javascript simply won't let you reassign a function while it's being executed.
TADA!!!

Categories