Signatur
Beschreibung
Die Eigenschaft length jeder Funktionsinstanz gibt an, wie viele Argumente die Funktion erwartet. Die Eigenschaft ist schreibgeschützt (writable: false), nicht aufzählbar (enumerable: false), aber konfigurierbar (configurable: true). Sie lässt sich also nicht per Zuweisung ändern, wohl aber mit Object.defineProperty().
Gezählt werden nur die Parameter vor dem ersten Parameter mit Standardwert. Ein Rest-Parameter (...args) zählt nie mit. Destrukturierte Parameter wie ({ a, b }) zählen jeweils als ein Parameter. Wie viele Argumente beim Aufruf tatsächlich übergeben werden, spielt keine Rolle. Das verrät nur arguments.length innerhalb einer normalen Funktion.
Typische Einsatzfälle sind Hilfsfunktionen aus der funktionalen Programmierung wie curry(), das Erkennen verschiedener Callback-Signaturen (zum Beispiel Express-Fehler-Middleware mit vier Parametern) und das Prüfen von Funktionen, die als Plug-in übergeben werden.
Gebundene Funktionen aus Function.prototype.bind() haben als length die ursprüngliche Anzahl minus der vorab gebundenen Argumente, aber nie weniger als 0. Der Function-Konstruktor selbst hat length === 1, und Function.prototype.length ist 0.
Rückgabewert
Beispiele
Grundlagen: Standardwerte und Rest-Parameter
const a = () => {};
const b = (x, y) => x + y;
const c = (x, y = 1, z) => x + y + z;
const d = (x, ...rest) => rest;
const e = ({ id, name }, [first]) => id;
console.log(a.length); // keine Parameter
console.log(b.length); // zwei Parameter
console.log(c.length); // Zählung endet bei y = 1
console.log(d.length); // Rest-Parameter zählt nicht
console.log(e.length); // Destrukturierung zählt je 1
Generisches Currying anhand von length
const curry = (fn) => {
const curried = (...args) =>
args.length >= fn.length
? fn(...args)
: (...more) => curried(...args, ...more);
return curried;
};
const volumen = (l, b, h) => l * b * h;
const cv = curry(volumen);
console.log(cv(2)(3)(4));
console.log(cv(2, 3)(4));
Middleware-Typ an der Signatur erkennen (Express-Stil)
const handlers = [
(req, res, next) => next(),
(err, req, res, next) => res.send(`Fehler: ${err.message}`)
];
handlers.forEach((h, i) => {
const typ = h.length === 4 ? 'Fehler-Handler' : 'normaler Handler';
console.log(`Handler ${i}: ${typ}`);
});
bind(), Schreibschutz und defineProperty
function summe(a, b, c) { return a + b + c; }
const plus10 = summe.bind(null, 10);
console.log(plus10.length);
summe.length = 99; // wird ignoriert (im Strict Mode TypeError)
console.log(summe.length);
Object.defineProperty(summe, 'length', { value: 5 });
console.log(summe.length);
console.log(Function.length, Function.prototype.length);
// Wichtig · Fallstricke
- Standardwerte beenden die Zählung:
(a = 1, b) => {}hat dielength0. Wer Funktionen perlengthunterscheidet (Currying, Middleware), bekommt bei Standardwerten oder Rest-Parametern leicht falsche Ergebnisse. - Schreibschutz:
fn.length = 3wird außerhalb des Strict Mode stillschweigend ignoriert. Im Strict Mode (also auch in ES-Modulen und Klassen) wirft die Zuweisung einenTypeError. - Nicht mit
arguments.lengthverwechseln:fn.lengthbeschreibt die Deklaration der Funktion,arguments.lengthdie Argumente eines konkreten Aufrufs. - Wrapper verlieren die Information: Decorators oder Hilfsfunktionen der Form
(...args) => fn(...args)haben immerlength === 0. Wenn die Stelligkeit wichtig ist, muss sie perObject.defineProperty()übernommen werden. - Eingebaute Funktionen: Hier ist
lengthin der Spezifikation festgelegt, z. B.Array.prototype.push.length === 1undMath.max.length === 2. Der Wert stimmt nicht immer mit der Zahl der möglichen Argumente überein. - Kompatibilität: Funktioniert in allen Browsern und in Node.js. Ab ES2015 ist die Eigenschaft konfigurierbar, in älteren Engines war sie es nicht.