Sichere Property-Prüfung ohne Fallstricke
obj.hasOwnProperty(key) sieht harmlos aus, bricht aber bei null-Prototyp-Objekten und bei überschriebenen Prototyp-Methoden. Object.hasOwn(obj, key) ist die statische, robuste Alternative, die genau diese Fallstricke umschifft und in modernem Code die Standardwahl für Property-Prüfungen sein sollte.
Inhaltsverzeichnis
- 1. Warum eine neue Methode für etwas so Simples?
- 2. Object.hasOwn: Syntax und Rückgabewert
- 3. Das null-Prototyp-Problem: wenn hasOwnProperty verschwindet
- 4. Überschriebene hasOwnProperty-Methoden als Angriffsfläche
- 5. Object.hasOwn mit Proxy-Objekten
- 6. Praxisfall: Sichere Objektiteration mit for...in
- 7. Vom JSON kommende Objekte prüfen
- 8. Migration im Bestandscode: wann sich der Umstieg lohnt
- 9. Object.hasOwn im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum eine neue Methode für etwas so Simples?
Auf den ersten Blick wirkt Object.hasOwn wie eine überflüssige Ergänzung: obj.hasOwnProperty(key) gibt es schon seit den Anfängen von JavaScript und macht scheinbar genau dasselbe. Der Unterschied liegt aber genau in dem Wort "scheinbar". hasOwnProperty ist eine Methode, die vom Prototyp geerbt wird, und genau diese Vererbung ist die Quelle mehrerer subtiler Bugs, die in echtem Code immer wieder auftreten.
Object.hasOwn löst das Problem, indem es die Prüfung als statische Funktion implementiert, die unabhängig vom geprüften Objekt selbst funktioniert. Statt eine Methode auf dem Objekt aufzurufen, das theoretisch manipuliert oder gar nicht vorhanden sein kann, übergibt man das Objekt als Argument an eine Funktion, die auf Object selbst lebt. Diese scheinbar kleine Verschiebung der Verantwortung ist der eigentliche Kern, warum Object.hasOwn in modernem JavaScript-Code die sicherere Wahl ist.
2. Object.hasOwn: Syntax und Rückgabewert
Die Syntax von Object.hasOwn ist bewusst einfach gehalten: Object.hasOwn(obj, prop) nimmt das zu prüfende Objekt als erstes und den Property-Namen als zweites Argument und gibt einen Boolean zurück, der genau angibt, ob das Objekt eine eigene, direkte Property mit diesem Namen besitzt. Vererbte Properties vom Prototyp werden dabei bewusst ignoriert, exakt wie bei der klassischen hasOwnProperty-Methode.
Der entscheidende Vorteil zeigt sich erst bei der Aufruf-Syntax: Object.hasOwn wird niemals auf dem zu prüfenden Objekt selbst aufgerufen, sondern immer auf Object. Das bedeutet, es ist völlig irrelevant, welchen Prototyp das übergebene Objekt hat, ob es eigene Methoden überschreibt oder ob es überhaupt eine funktionierende Prototyp-Kette besitzt. Diese Entkopplung ist der eigentliche technische Fortschritt gegenüber der alten Methode.
const config = { debug: true, retries: 3 };
// Object.hasOwn: static call, independent of the object's prototype
console.log(Object.hasOwn(config, "debug")); // true
console.log(Object.hasOwn(config, "toString")); // false — inherited, not own
// Old approach: method call on the object itself
console.log(config.hasOwnProperty("debug")); // true, works fine here
3. Das null-Prototyp-Problem: wenn hasOwnProperty verschwindet
Der offensichtlichste Fehlerfall für hasOwnProperty tritt bei Objekten auf, die mit Object.create(null) erzeugt wurden. Solche Objekte besitzen bewusst keinen Prototyp, was in sicherheitsrelevantem Code häufig gewünscht ist, um Prototype Pollution von vornherein auszuschließen. Das Problem: ohne Prototyp gibt es auch keine geerbte hasOwnProperty-Methode, und der Aufruf obj.hasOwnProperty(key) wirft eine TypeError-Exception, weil die Methode schlicht nicht existiert.
Object.hasOwn hat mit diesem Fall überhaupt kein Problem, weil die Prüfung niemals auf dem Objekt selbst aufgerufen wird. Ein null-Prototyp-Objekt lässt sich mit Object.hasOwn genauso sicher prüfen wie ein gewöhnliches Objekt-Literal. Wer defensiv programmiert und häufig Object.create(null) für Konfigurationsobjekte oder Lookup-Tabellen einsetzt, um Kollisionen mit Prototyp-Properties zu vermeiden, profitiert hier direkt und ohne zusätzlichen Aufwand.
// Object.create(null) has no prototype at all
const dictionary = Object.create(null);
dictionary.hello = "welt";
// This throws: TypeError, hasOwnProperty does not exist on this object
try {
dictionary.hasOwnProperty("hello");
} catch (err) {
console.error(err.message); // dictionary.hasOwnProperty is not a function
}
// Object.hasOwn works regardless of the object's prototype chain
console.log(Object.hasOwn(dictionary, "hello")); // true
console.log(Object.hasOwn(dictionary, "world")); // false
4. Überschriebene hasOwnProperty-Methoden als Angriffsfläche
Ein zweiter, subtilerer Fehlerfall entsteht, wenn ein Objekt selbst eine Property namens hasOwnProperty definiert, die nicht die geerbte Methode ist. Das passiert häufiger als man denkt, etwa bei Objekten, die dynamisch aus unsicheren Datenquellen wie Formulareingaben oder JSON-Payloads zusammengesetzt werden. Ist in diesen Daten ein Schlüssel hasOwnProperty enthalten, überschreibt er die geerbte Methode, und der nächste Aufruf von obj.hasOwnProperty(key) ruft plötzlich nicht mehr die erwartete Prüfung auf, sondern den überschriebenen Wert.
Object.hasOwn ist gegen diese Art von Manipulation vollständig immun, weil die Prüfung nie auf dem potenziell kompromittierten Objekt aufgerufen wird. In sicherheitskritischem Code, der mit Nutzereingaben oder externen APIs arbeitet, ist das ein reales Härtungsmerkmal und kein theoretisches Detail. Wer Objekte aus unsicheren Quellen prüft, sollte konsequent Object.hasOwn statt der Methode auf dem Objekt verwenden.
5. Object.hasOwn mit Proxy-Objekten
Proxy-Objekte fügen eine weitere Ebene der Komplexität hinzu. Ein Proxy kann den has-Trap und den getOwnPropertyDescriptor-Trap implementieren, um das Verhalten von Property-Prüfungen komplett anzupassen. Object.hasOwn respektiert diese Traps korrekt, weil es intern auf [[GetOwnProperty]] basiert, denselben internen Mechanismus, den auch Object.getOwnPropertyDescriptor nutzt. Ein Proxy, der bestimmte Properties gezielt verstecken oder simulieren will, funktioniert also mit Object.hasOwn genau wie erwartet.
Das ist relevant für Frameworks und Bibliotheken, die reaktive Objekte über Proxys implementieren, etwa Zustandsverwaltung in modernen Frontend-Architekturen. Prüft eine solche Bibliothek intern mit Object.hasOwn, statt sich auf die Objektmethode zu verlassen, bleibt das Verhalten auch dann korrekt, wenn Anwender eigene Proxy-Wrapper um die reaktiven Objekte legen. Diese Konsistenz war mit der alten Methode nicht garantiert.
const hidden = new Proxy({ secret: 42, visible: 1 }, {
getOwnPropertyDescriptor(target, prop) {
if (prop === "secret") return undefined; // hide this property
return Object.getOwnPropertyDescriptor(target, prop);
}
});
console.log(Object.hasOwn(hidden, "secret")); // false — trap respected
console.log(Object.hasOwn(hidden, "visible")); // true
6. Praxisfall: Sichere Objektiteration mit for...in
Die klassische Kombination for...in mit hasOwnProperty-Filterung ist ein jahrealtes Pattern, um bei der Iteration über ein Objekt nur die eigenen Properties zu berücksichtigen und geerbte Prototyp-Properties zu ignorieren. In Code, der mit generischen Objekten unbekannter Herkunft arbeitet, sollte diese Filterung immer mit Object.hasOwn statt der Methode auf dem Objekt erfolgen, um gegen die zuvor beschriebenen Fallstricke abgesichert zu sein.
In neuerem Code ist Object.entries oder Object.keys häufig die bessere Wahl, weil beide von sich aus nur eigene, aufzählbare Properties liefern und keine Filterung benötigen. Trifft man aber auf for...in-Schleifen in Bestandscode, etwa beim Durcharbeiten älterer Codebasen, ist der Austausch der Filterbedingung gegen Object.hasOwn eine risikoarme, punktuelle Verbesserung.
const merged = Object.assign(Object.create({ inherited: "from prototype" }), {
own1: "a",
own2: "b"
});
// Safe iteration: only own properties, robust against overridden methods
for (const key in merged) {
if (Object.hasOwn(merged, key)) {
console.log(key, merged[key]); // own1 a / own2 b — "inherited" is skipped
}
}
7. Vom JSON kommende Objekte prüfen
Objekte, die aus JSON.parse stammen, haben immer den normalen Object.prototype und funktionieren mit beiden Methoden in den meisten Fällen problemlos. Die Ausnahme entsteht, sobald das JSON selbst Schlüssel wie hasOwnProperty, constructor oder __proto__ enthält, etwa bei Nutzereingaben, die in ein JSON-Objekt serialisiert wurden. In diesem Fall überschreibt der geparste Wert die geerbte Methode auf demselben Weg wie im vorherigen Abschnitt beschrieben.
Wer Konfigurationsdateien, Webhook-Payloads oder Formulardaten als JSON verarbeitet, sollte grundsätzlich davon ausgehen, dass beliebige Schlüsselnamen vorkommen können. Object.hasOwn macht die Property-Prüfung in diesen Fällen unabhängig vom Inhalt der Daten und schließt eine ganze Klasse von Fehlern aus, die sonst erst in der Produktion auffallen würden, wenn genau der "falsche" Schlüsselname im JSON auftaucht.
8. Migration im Bestandscode: wann sich der Umstieg lohnt
Ein pauschaler Ersatz jeder hasOwnProperty-Verwendung durch Object.hasOwn ist selten notwendig, aber an bestimmten Stellen im Code hat der Umstieg klaren Mehrwert. Besonders relevant ist er bei Funktionen, die generische Objekte aus externen Quellen entgegennehmen, bei Utility-Funktionen in gemeinsam genutzten Bibliotheken und bei jedem Code, der mit Object.create(null) erzeugten Objekten arbeitet.
Bei internem Code, der ausschließlich mit selbst kontrollierten, einfachen Objekt-Literalen arbeitet, bringt der Umstieg wenig praktischen Nutzen, schadet aber auch nicht. Ein guter Kompromiss ist, Object.hasOwn als neuen Standard für alle neu geschriebenen Property-Prüfungen festzulegen, ohne bestehenden, funktionierenden Code aus reiner Konsequenz umzuschreiben. Linter-Regeln wie eslint-plugin-es-x können den Umstieg für neue Codeteile automatisch erzwingen.
9. Object.hasOwn im direkten Vergleich
Die folgende Tabelle stellt die wichtigsten Unterschiede zwischen der klassischen Methode und der neuen statischen Funktion gegenüber und zeigt, in welchen Situationen der Unterschied tatsächlich praktisch relevant wird.
| Situation | obj.hasOwnProperty(key) | Object.hasOwn(obj, key) | Ergebnis |
|---|---|---|---|
| Object.create(null) | TypeError | true / false | Object.hasOwn funktioniert immer |
| Eigenes hasOwnProperty im Objekt | Falsches Ergebnis | Korrektes Ergebnis | Object.hasOwn ist immun |
| Proxy mit eigenen Traps | Abhängig vom Trap-Setup | Respektiert Traps korrekt | Beide möglich, hasOwn konsistenter |
| Gewöhnliches Objekt-Literal | Funktioniert | Funktioniert | Kein praktischer Unterschied |
| Lesbarkeit im Code | Methodenaufruf, vertraut | Statischer Aufruf, expliziter | Geschmacksfrage, leichter Vorteil hasOwn |
In der Praxis zeigt sich: bei einfachen, selbst kontrollierten Objekten ist der Unterschied kosmetisch, bei Objekten unbekannter Herkunft wird Object.hasOwn zur echten Absicherung gegen Laufzeitfehler und Manipulation.
Mironsoft
Robuster JavaScript-Code und Absicherung gegen Laufzeitfehler
Code, der auch mit unsicheren Daten stabil bleibt?
Wir prüfen bestehenden JavaScript-Code auf fragile Property-Zugriffe, ersetzen veraltete Muster durch robuste Alternativen wie Object.hasOwn und härten eure Anwendungen gegen Prototype Pollution und manipulierte Objekte.
Security-Review
Objekt-Zugriffe und Prototyp-Ketten auf Manipulationsrisiken prüfen
Code-Modernisierung
Veraltete Property-Prüfungen durch moderne ES2022-Patterns ersetzen
Lint-Regeln
Automatisierte ESLint-Regeln für konsistente Property-Zugriffe einrichten
10. Zusammenfassung
Object.hasOwn löst ein Problem, das viele Entwickler jahrelang unterschätzt haben: die geerbte Methode hasOwnProperty kann durch null-Prototypen fehlen oder durch eigene Objekt-Properties überschrieben werden, und beide Fälle führen zu Laufzeitfehlern oder falschen Prüfergebnissen. Als statische Funktion auf Object ist Object.hasOwn gegen beide Fallstricke immun, weil die Prüfung nie auf dem potenziell kompromittierten Objekt selbst stattfindet.
Für neuen Code ist Object.hasOwn die klare Empfehlung, besonders bei Funktionen, die generische Objekte aus externen Quellen wie JSON-Payloads, Formulardaten oder Konfigurationsdateien entgegennehmen. Bei Objekten mit Object.create(null) oder Proxy-Wrappern ist der Umstieg nicht nur eine Stilfrage, sondern verhindert konkrete Bugs, die sonst erst in der Produktion sichtbar werden.
Object.hasOwn — Das Wichtigste auf einen Blick
Grundprinzip
Statische Funktion Object.hasOwn(obj, key) statt Methodenaufruf auf dem Objekt selbst, unabhängig vom Prototyp.
Null-Prototyp-Objekte
Funktioniert korrekt bei Object.create(null), während hasOwnProperty dort eine TypeError-Exception wirft.
Manipulationssicherheit
Immun gegen eigene hasOwnProperty-Properties im geprüften Objekt, relevant bei unsicheren Datenquellen.
Praxis-Empfehlung
Als Standard für neuen Code festlegen, besonders bei generischen Objekten und JSON-Payloads.