As the title says I'm wondering if it's possible to get the parameters of a passed function. After hours of searching and looking at similar questions I'm still no closer, so I'll attach a simple example rather then what I'm working on - as I'm starting to suspect it's not possible.
Intended global function
function getTransaction(anyMethod)
{
db.transaction
(
function(transaction)
{
anyMethod(transaction);
},
function errorCB(err) {
redirectToLoginWithError("Error processing SQL");
},
function successCB() {
;//alert("Success!");
}
);
}
Functions to be called
function iWork(tx)
{
tx.doSomething();
}
function iDontWork(tx, param1, param2)
{
tx.doSomething(param1, param2);
}
Actual call
// Works fine
getTransaction(iWork);
// The problem
getTransaction(iDontWork, value1, value2);
getTransaction(iDontWork2, value1, value2, ..., valueX);
I've tried several different approaches, but none have proved successful so far. The closest (although not very) have been
getTransaction(function(){iDontWork(value1, value2)}));
This does call the correct function via the getTransaction, but does not pass the parameters correctly: Params (value1, value2) are kept, but the transaction object is lost / undefined. I can see why this does happen, but I cannot see any solution to it. All said, I'm also open to that the getTransaction should be scrapped and re-written somehow. The point is to get a flexible method that scales well.
Simply refactor getTransation to take a function and an array of arguments. Prepend the transaction variable to the argument array and call the function using apply:
function getTransaction(anyMethod, methodArgs) {
var someFunction = anyMethod;
// if no args provided, use an empty array
methodArgs = methodArgs || [];
db.transaction (
function(transaction) {
// transaction is always the first arg; prepend it to the arg list
methodArgs.unshift(transaction);
// call method with argument array
anyMethod.apply(null, methodArgs);
},
// ...
);
}
Simply use it with:
doTransaction(iDontWork, [param1, param2]);
doTransaction(iWork);
EDIT:
As #rambo coder pointed out, you could just use regular arguments (instead of an array of arguments) by slicing arguments:
function getTransaction(anyMethod) {
var someFunction = anyMethod;
db.transaction (
function(transaction) {
var methodArgs = arguments.slice(1);
methodArgs.unshift(transaction);
anyMethod.apply(null, methodArgs);
},
...
This way lets you supply arguments directly to getTransaction, as you do in your example (doTransaction(iDontWork, param1, param2);), instead of putting them in an array.
getTransaction(function (x) {
iDontWork(x, value1, value2);
});
Your getTransaction assumes that its single argument is a function that takes one parameter. You need to create a new function that takes one parameter, but also includes the specific parameter values you want (namely value1 and value2).
The above uses an anonymous function; you could also do it with a named function:
function forwarder(x) {
iDontWork(x, value1, value2);
}
getTransaction(forwarder);
You can do it by creating partial functions:
function iDontWork(param1, param2){
return function(tx) {
tx.doSomething(param1, param2);
}
}
And:
getTransaction(iDontWork(value1, value2));
Related
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.
I want to call a javascript function in Action script, something like this:
ExternalInterface.call('a_js_function', param1, another_js_function);
I want the javascript function a_js_function takes in two params, one is a string, another one is a callback function. So I can call the js function like this:
function a_js_function(testStr, callback) {
console.log(testStr);
callback(testStr);
}
function another_js_function(str) {
console.log(str);
}
What is the correct way to do this?
Problem solved, it turns out the second I passed in is a string, in javascript I have to turn string into function in order to call it.
call like this
try {
ExternalInterface.call('a_js_function', param1, another_js_function);
} catch(e:Error) {
trace(e)
}
and for more information see this
Since flash does not have any reference to the javascript function another_js_function you need to pass the function name as a string then access it using brackets on whichever namespace. I used global variables for simplicity but it can be any object/namespace
another_js_function = function(testStr) {
alert(testStr);
}
a_js_function = function(testStr, callback) {
console.log( this.window );
window[callback].call(this, testStr); // pass scope?
// OR
window[callback](testStr);
}
// Simulating call from Flash
a_js_function("howdy y'all", "another_js_function");
In Action: http://jsfiddle.net/3n1gm4/Np3bW/
My series of methods are like so :
onUpdateAcrossDown ( findAcrossAndDownWords( across_index, down_index ) )
I want to reuse findAcrossAndDownWords, so I'd like it to return my two objects that I can pass into other methods if need be.
findAcrossAndDownWords: function(across_index, down_index) {
across_word = across_index[0] // <-- not real, just representing that it becomes an object here.
down_word = down_index[0]
return [across_word, down_word] // <-- This is where my problem is. Not sure how to return a double param for my parent function.
}
The trouble is, the return I am using does not properly pass across_word, down_word .
onUpdateAcrossDown: function(across_word, down_word) {
// How do I get across_word and down_word here properly?
If you want to use the values in an array as parameters to a function, you have to call the function with .apply()
var results = findAcrossAndDownWords( across_index, down_index );
onUpdateAcrossDown.apply(whatever, results);
The .apply() method takes two arguments: the value to use for this in the called function, and an array containing the parameters to pass.
You could, instead of nesting calls, pass the second function as an argument:
findAcrossAndDownWords(across_index, down_index, onUpdateAcrossDown);
function findAcrossAndDownWords(object1, object2, callNext)
{
//do stuff
return callNext(object1, object2);
}
Or, change the function definition of the second function to:
function UpdateAcrossDown(anArray)
{
var obj1 = anArray[0], obj2 = anArray[1];
}
Or, if you're allways going to call the same function:
function findAcrossAndDownWords(object1, object2, callNext)
{
//do stuff
return UpdateAcrossDown(object1, object2);//loses call context
return UpdateAcrossDown.apply(this,arguments);//preserve called context
//or even
return UpdateAcrossDown.apply(this,[object1,object2]);//preserve called context
}
This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
This question looks like a duplicate, as the title is nearly replicated. But, my issue seems simpler and I can't find the answer to it.
I have a Javascript function that executes another callback function, it works like this:
<script type='text/javascript'>
firstfunction(callbackfunction);
</script>
where callback function is defined as:
callbackfunction(response) {
if (response=='loggedin'){
// ... do stuff
}}
but I want it to be something like this:
callbackfunction(response, param) {
if (response=='loggedin'){
// ... do stuff with param
}}
My question is, does it work to pass the parameter like this:
<script type='text/javascript'>
firstfunction(callbackfunction(param));
</script>
or am I doing it wrong?
In direct answer to your question, this does not work:
firstfunction(callbackfunction(param));
That will execute callbackfunction immediately and pass the return value from executing it as the argument to firstfunction which is unlikely what you want.
It is unclear from your question whether you should just change firstfunction() to pass two parameters to callbackfunction() when it calls the callback or whether you should make an anonymous function that calls the callback function with arguments.
These two options would look like this:
function firstfunction(callback) {
// code here
callback(arg1, arg2);
}
firstfunction(callbackfunction);
or
function firstfunction(callback) {
// code here
callback();
}
firstfunction(function() {
callbackfunction(xxx, yyy);
});
Use an anonymous function:
function foo( callback ) {
callback();
}
function baz( param ) {
console.log( param );
}
foo( function(){ baz('param') });
Adding parameters when calling a function.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply
xdaz already answered the simple version.
Here is an example with variable amount of parameters.
function someObject(){
this.callbacks=new Array();
this.addCallback=function(cb){
this.callbacks[this.callbacks.length]=cb
}
this.callCallbacks=function(){
//var arr=arguments; this does not seem to work
//arr[arr.length]="param2";
var arr = new Array();
for(i in arguments){
arr[i]=arguments[i];
}
arr[arr.length]="another param";
i=0;
for(i in this.callbacks){
this.callbacks[i].apply(null,arr);
//this.callbacks[i].apply(this,arr);
//this is a ref to currrent object
}
}
this.callCallbacksSimple=function(arg){
for(i in this.callbacks){
this.callbacks[i](arg,"simple parameter");
}
}
}
function callbackFunction(){
for(i in arguments){
console.log("Received argument: " + arguments[i]);
}
}
var ObjectInstance=new someObject();
ObjectInstance.addCallback(callbackFunction);
ObjectInstance.callCallbacks("call callbacks");
ObjectInstance.callCallbacksSimple("call callbacks");
function is key word, you can't use it as function name.
Let say your function name is foo, then you could do like below:
var param = 'what ever';
foo(function(response) {
callbackfunction(response, param);
});
I think this is what you're looking for.
Lets say you're using jQuery ajax to do something, and you're passing it named callbacks. Here we have an onError callback that you might use to log or handle errors in your application. It conforms to the jQuery Ajax error callback signature, except for an extra parameter that you might have wanted to add at the back
function onError(jqXHR, textStatus, errorThrown, yourOwnVariableThing) {
console.error('Something went wrong with ' + yourOwnVariableThing);
}
this is where your function would be called - but you want an extra parameter
$.ajax("/api/getSomeData/")
.done(onDone)
.fail(onError)
.always(onComplete);
So this is what you can do to add the extra parameter
$.ajax("/api/getSomeData/")
.done(onDone)
.fail(onError.bind(this, arguments[0], arguments[1], arguments[2], 'Moo Moo');
.always(onComplete);
arguments is an array in JavaScript that contains all arguments passed to a function, and so you're just passing those arguments along to the callback.
Arguments
Bind
This question in summary is to figure out how to pass variables between javascript functions without: returning variables, passing parameters between primary functions, using global variables, and forcing function 1 to wait for function 2 to finish. I figured out a jQuery solution and posted in below (in the answers section).
Old Post: I initialize a set of four functions, each calling on each other in a different way. At the end of it, I need the final modified product (an array) returned to the initializing function.
Global variables don't force the initial function to wait. And returning it backwards four times doesn't work either. How do you pass a modified variable back to its initializing function, if you can't return it? Or why isn't it returning?
(the maze starts at initFunctionA, ends at functionD)
classOne = {
initFunctionA : function() {
classTwo.functionB(functionD, array);
// I NEED ACCESS TO ARRAY2 HERE
},
functionD : function(data, array) {
var array2 = // modifications to array
}
}
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
}
Change your callback (at the call site) such that you capture the return value of functionD. Then, change functionD so that it returns array2. I've added this access to the example below as a convenience. (Also, be sure to include semicolons where "required" if you want to make JSLint happy.)
classOne = {
initFunctionA : function() {
var self = this;
classTwo.functionB(function() {
var array2 = functionD.apply(self, arguments);
// ACCESS ARRAY2 HERE
}, array);
},
functionD : function(data, array) {
var array2 = // modifications to array
return array2;
}
};
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
};
You can't make it work with a pattern like you've written there; it's simply not possible in Javascript because there's no such thing as "waiting". Your ajax code has to take a callback parameter (which you've got, though it's not clear where it comes from or what it does), and that initial function should pass in code to do what you need with the array after the ajax call finishes.
I would use an object constructor:
function ClassOne() {
this.array2 = [];
}
ClassOne.prototype.initFunctionA = function() {
// ...
}
ClassOne.prototype.functionD = function(data, array) {
// Can use array2 EX: this.array2
}
var classOne = new ClassOne();
This is how I understand your problem:
classTwo handles an AJAX call and may modify the result. classOne makes use of classTwo to get some data and needs the resulting data.
If so, how's this:
classOne = {
initFunctionA : function() {
var array = ['a','b','c'];
classTwo.functionB(this.functionD, array);
},
functionD : function(data, array) {
// This function is called when the AJAX returns.
var array2 = // modifications to array
}
}
{...}
classTwo = {
functionB : function(callback, array) {
$.ajax({
success: function(ret){
classTwo.functionC(ret, callback, array)
}
});
},
functionC : function(ret, callback, array) {
callback(ret.data.x, array);
}
}
So classOne.initFunctionA calls classTwo.functionB which sets up an ajax call. When the ajax call completes successfully, classTwo.functionC is called with the result and the initial array. From here, classOne.functionD is called with ret.data.x and the array.
Okay! I found a way to pass variables between functions without:
making global variables
making object properties (Chaos's solution)
passing parameters
These three were suggested here as the only ways.
Accessing variables from other functions without using global variables
But, if you you can't pass parameters directly, and you need one function to wait for the other (i.e, can't rely on references), and you're using asynchronous calls to the server in an intermediate function, then your only solution is:
Using jQuery...
Create this object in the DOM (dynamically if you don't want to muddy your markup):
<div id='#domJSHandler" style="display: none;"></div>
Then in the function that must wait:
//Function & Class Set 2
$('#domJSHandler').bind('proceedWithAction', function(event, param1, param2) {
// action set 2
});
And in the function to be waited on:
//Function & Class Set 1
// action set 1
$('#domJSHandler').triggerHandler('proceedWithAction', [param1, param2]);
Essentially encase the last actions you need to perform in a jQuery bind custom event on an invisible DOM object. Trigger that event from JS with jQuery's triggerHandler. Pass your parameters and voila!
I'm sure SO will give me crap for this (and for narcissistically accepting my own answer) but I think it's pretty brilliant for a uber-newbie and it worked for me.
So :p Stack Overflow
(jk You've all saved my ass many times and I love you all :)