What is the equivalent of Lua's ellipsis in JavaScript?
Asked Answered
F

4

5

In Lua, a function like this would be valid:

function FuncCallHack(Func, ...)
    return Func(...)
end

Is there a way I could do this in JavaScript? ... means "all unindexed parameters in the form of an ungrouped array" to those unfamiliar with Lua. I have tried ... in JavaScript, and it appeared to be nonfunctional, and as Google doesn't like searching for special characters, it's not much help.

Fala answered 1/1, 2014 at 19:0 Comment(2)
#1959540Fallingout
Not a repeat question, read closer, and understand before commenting please.Fala
L
5

JavaScript has the arguments pseudo-array and the apply function; you can do that like this:

function FuncCallHack(Func) {
    return Func.apply(this, [].slice.call(arguments, 1));
}

here's how that works:

  1. arguments - This is a pseudo-array containing all of the arguments passed to the function by the calling code (including the format argument Func).

  2. [].slice.call(arguments, 1) is a way to get an array of all of the arguments except the first one. (It's a common idiom. It works by applying the Array#slice method to the arguments pseudo-array, using Function#call [which is a lot like Function#apply below, it just accepts the args to pass on differently].) Sadly, arguments itself doesn't necessarily have a slice method because it's not really an array.

  3. Then we use the Function#apply method (all JavaScript functions have it) to call Func using the same this value that was used for the call to FuncCallHack, and passing on all of the arguments except Func to it.

You could also define it slightly differently:

function FuncCallHack(Func, args) {
    return Func.apply(this, args);
}

...which is still really easy to use:

FuncCallHack(SomeFunction, [1, 2, 3]);
// Note this is an array --^-------^
Lowder answered 1/1, 2014 at 19:5 Comment(4)
Note that [].slice.call(arguments, 1) must be used instead of arguments.slice(1) because arguments is not a real Array object.Directoire
Hacky, but works, ty :-) good thing the code I'm running is backend stuff, so hacky is permissible. it would be less hacky if you could get the number of named parameters, and slice to that number, instead of a hard coded number to slice by, but much appreciated.Fala
A little confused, possibly a tail call issue, but your code evaluates to undefined args, but placing the slice in a variable, and passing it to the apply call works, I heard JS doesn't have tail calls, perhaps this is a case of that?Fala
@JohnDoe: I've used this pattern hundreds of times, there's no reason the args should be undefined, I suspect that's something else (perhaps something async?). Example: jsbin.com/iXIxUpo/1 FWIW, I usually grab the slice function once and reuse it: jsbin.com/iXIxUpo/2 Re knowing how many formal parameters there are, you can get that from FuncCallHack.length: return Func.apply(this, [].slice.call(arguments, FuncCallHack.length); - jsbin.com/iXIxUpo/3 Have fun!Lowder
S
3

Javascript does not yet support this feature.

Instead, you can loop through the arguments array-like object to see every parameter.

To get an array of all of the parameters after the first two (assuming two named parameters), you can write

Array.prototype.slice.call(arguments, 2)
Swelter answered 1/1, 2014 at 19:3 Comment(0)
P
1

With ES6 comes native support for this, it's named Rest parameters and Spread operator:

function FuncCallHack(Func, ...args) {
    return Func(...args)
}

Feature availability.

Prelusive answered 6/11, 2015 at 2:7 Comment(0)
F
0

This may not work everywhere, but it's a neat trick to succinctly replicate {...} in JavaScript.

function varg(f, a) {
    f = f || varg.caller || arguments.caller;
    a = a || f.arguments;
    return Array.prototype.slice.call(a, f.length);
}

function f(a) {
    var b;
    // varg() could be used in one of the following ways:
    b = varg();  // Non-standard: uses caller.
    b = varg(f); // Not strict compliant: uses a function's arguments property.
    b = varg(f, arguments); // Should be safe to use everywhere.
    return b;
}

console.log(f(1));
console.log(f(1, 2));
console.log(f(1, 2, 3));

What's going on here is that within varg(), the calling function is inferred from caller and its arguments are determined by checking its arguments property. The argument pseudo-array is then sliced into a real array, starting from f.length, which represents the arity, or how many arguments is expected of the calling function, thus avoiding the need for any hard-coded magic numbers.

However, if the problem you're trying to solve is just redirecting a function's arguments into another's, then T.J. Crowder's answer is more appropriate.

function FuncCallHack(Func) {
  return Func.apply(this, [].slice.call(arguments, 1));
}
Fortunate answered 1/1, 2014 at 19:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.