Get a function's arity
Asked Answered
F

5

69

In Javascript, how can one determine the number of formal parameters defined for a function?

Note, this is not the arguments parameter when the function is called, but the number of named arguments the function was defined with.

function zero() {
    // Should return 0
}

function one(x) {
    // Should return 1
}

function two(x, y) {
    // Should return 2
}
Fidellia answered 31/1, 2011 at 6:21 Comment(1)
What is the arity of function(){ return arguments[0]; } ?Fuze
H
85
> zero.length
0
> one.length
1
> two.length
2

Source

A function can determine its own arity (length) like this:

// For IE, and ES5 strict mode (named function)
function foo(x, y, z) {
    return foo.length; // Will return 3
}

// Otherwise
function bar(x, y) {
    return arguments.callee.length; // Will return 2
}
Hyper answered 31/1, 2011 at 6:25 Comment(9)
I intended to answer my own question since it wasn't on Stack Overflow but you beat me to it! I will update your answer with technique for a function to determine its own arity.Fidellia
You mean arguments.callee.length?Brume
Note that this is not the same as arguments.length, which is the number of arguments actually received.Hyper
Yes, that is why I said "arity," so people who know what they are searching for don't have to wade through the beginner stuff about arguments.Fidellia
@jhs: Note also that arguments.callee throws an error in ECMAScript 5 strict mode, meaning it has effectively been removed from the language.Priedieu
@jhs: The way to do it in ES5 strict will be to use a function declaration or named function expression to allow you to refer to the function by name: var foo = function bar(x, y, z) { return bar.length; };. Because of issues in IE, it's best to avoid named function expressions in non-ES5 environments.Priedieu
Thanks, Tim. I was wondering because I had heard that arguments.callee breaks a very useful security environment that a function closure would set up. I will amend the answer.Fidellia
@TimDown, please, can you explain about IE bug ?Ayotte
With the introduction of default params in ES6, the length property would not work as expected: (function foo(a, b = 'default', c) {}).length // 1, only parameters before the first one with a default value are countedBezanson
C
16

As is covered in other answers, the length property tells you that. So zero.length will be 0, one.length will be 1, and two.length will be 2.

As of ES2015, we have two wrinkles:

  • Functions can have a "rest" parameter at the end of the parameter list which gathers up any arguments given at that position or afterward into a true array (unlike the arguments pseudo-array)
  • Function parameters can have default values

The "rest" parameter isn't counted when determining the arity of the function:

function stillOne(a, ...rest) { }
console.log(stillOne.length); // 1

Similarly, a parameter with a default argument doesn't add to the arity, and in fact prevents any others following it from adding to it even if they don't have explicit defaults (they're assumed to have a silent default of undefined):

function oneAgain(a, b = 42) { }
console.log(oneAgain.length);    // 1

function oneYetAgain(a, b = 42, c) { }
console.log(oneYetAgain.length); // 1
Constituent answered 15/12, 2016 at 18:57 Comment(2)
Thanks! This is a great update. I think for ...rest, while it hides the true arity, the .length property is still useful. But in the case of default parameters, do you know any workarounds, or even just a way to detect that default parameters are being used at all?Fidellia
@JasonSmith: Nothing that doesn't rely on decompilation (e.g., Function#toString).Constituent
F
12

A function's arity is stored in its .length property.

function zero() {
    return arguments.callee.length;
}

function one(x) {
    return arguments.callee.length;
}

function two(x, y) {
    return arguments.callee.length;
}

> console.log("zero="+zero() + " one="+one() + " two="+two())
zero=0 one=1 two=2
Fidellia answered 31/1, 2011 at 6:25 Comment(0)
S
1

The arity property used to return the number of arguments expected by the function, however, it no longer exists and has been replaced by the Function.prototype.length property.

Songstress answered 18/12, 2017 at 2:39 Comment(5)
Do you have any source for that claim? I can't find .arity anywhere. Even in version 1 of the ECMAScript standard (1997) it was .length.Aqaba
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Dobbs
@Dobbs Is that purposefully pointing to a 404?Stopgap
web.archive.org/web/20190329051824/https://…Dobbs
Also this tiny mention in the current docs: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Flores
P
0

Yes, fn.length returns what JS can discern as a function's arity. But since a function can include optional args, rest args or rely on the arguments object, the length cannot be trusted and should be used only in isolated circumstances.

For example, I implement a curry function in my lib which uses length by default, but the overload (e.g. curry(map, 2)) allows me to override the arity.

And that's the crux of it. The seeming usefulness of length is how it can be used to compose higher-order functions, but since length cannot be trusted, said higher-order function must allow an override of the default.

Since you're dealing with partial application and rest args (totally confounding what an acceptable length might be) and a host of compositions transforming one function into another, you can't trust length. This is further complicated by the possibility the function is overloaded and supports multiple arities.

When it comes to any given function the programmer (not the runtime) must have an intimate knowledge of its arity(ies).

The short of it: length is too unreliable for practical use that it ought not have been provided in the first place.

Paraesthesia answered 18/7 at 15:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.