Mach
Mach

Reputation: 67

Use my function in itself and return in 'correct' order

I have this function

var foo = function(){
  var args = Array.prototype.slice.call(arguments, 0);

  for (var i = 0; i < args.length; i++) {
    console.log(args[i]);
  }
};

that's used like this

foo(1, 2, 3, 4, 5, 6, 7, 8);

It's outcome

enter image description here

But I want it's usage to work like this, and get the same outcome

foo(1, 2, foo(3, 4, 5), 6, 7, 8);

Yet the out come for this is

enter image description here

Thanks in advance

Mach

Upvotes: 0

Views: 56

Answers (3)

T.J. Crowder
T.J. Crowder

Reputation: 1075059

But I want it's usage to work like this, and get the same outcome

foo(1, 2, foo(3, 4, 5), 6, 7, 8);

You can't. That line is equivalent to this:

var tmp = foo(3, 4, 5);
foo(1, 2, tmp, 6, 7, 8);

That is, first the foo(3, 4, 5) bit runs, and then the foo(1, 2, mumble, 6, 7, 8) bit runs.

There are games you can play to defer execution, but they will tend to be very specific to what you're actually doing (which I assume isn't just outputting numbers in order).

For instance, a game you could play here would be to have foo detect whether its arguments are functions and, if so, call them; then you could use Function#bind (or similar) to create functions that, when called, will have the arguments you want. That looks like this:

var foo = function(){
  var args = Array.prototype.slice.call(arguments, 0);
  var arg;

  for (var i = 0; i < args.length; i++) {
    arg = args[i];
    if (typeof arg === "function") {
        arg();
    } else {
        console.log(arg);
    }
  }
};

and then used like this:

foo(1, 2, foo.bind(undefined, 3, 4, 5), 6, 7, 8);

Live Example (source)

That works because Function#bind doesn't call the function, it creates a new function that, when called, will get called with the arguments you gave bind (the first argument is what this will be during the call; if you don't have anything specific it needs to be, use undefined or null). So in effect when we do this:

foo(1, 2, foo.bind(undefined, 3, 4, 5), 6, 7, 8);

...we're doing this:

var tmpFunction = foo.bind(undefined, 3, 4, 5);
foo(1, 2, tmpFunction, 6, 7, 8);

(Function#bind is an ES5 feature present in all modern browsers except IE8 (which while not "modern" is still in significant use), but it can be correctly "shimmed" using es5-shim or similiar.)

(Trivia: This thing where you create a function with some of its arguments "baked into" it is called currying a function, so named after the mathematician Haskell Curry. [And yes, that's where the programming language Haskell gets its name.])

Upvotes: 3

Andrei CACIO
Andrei CACIO

Reputation: 2129

First you have to return the args in your foo() as so:

var foo = function(){
  var args = Array.prototype.slice.call(arguments, 0);
  for (var i = 0; i < args.length; i++) {
    console.log(args[i]);
  }
  return args;
};

But, even so you would get an Array as the 3rd element of your array when you call:

foo(1, 2, foo(3, 4, 5), 6, 7, 8);

You will have to filter your arguments so if there's an array found among your arguments, you should split that into scalars and then pass them to the slice method.

Hope this helped, keep me posted.

Upvotes: 0

heikkim
heikkim

Reputation: 2975

You're calling foo(3,4,5) and putting it's return value to the second call to foo(...). Your code can be written as:

var ret = foo(3,4,5);
foo(1, 2, ret, 6, 7, 8);

I am unaware what console.log accepts as arguments, but if it can handle a function, you could do:

var func = function() { foo(3, 4, 5); };
foo(1, 2, func, 6, 7, 8);

Upvotes: 0

Related Questions