最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Can you pass parameters to a function without invoking it right away? - Stack Overflow

programmeradmin3浏览0评论

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!

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!

Share Improve this question asked Feb 4, 2014 at 10:56 Ryan WilliamsRyan Williams 7056 silver badges11 bronze badges 1
  • how about extending your function definition with a params object, where you can define optional parameters for your function, e.g. {function1: [param1,param2]}. – nietonfir Commented Feb 4, 2014 at 10:59
Add a comment  | 

8 Answers 8

Reset to default 6

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]
发布评论

评论列表(0)

  1. 暂无评论