JavaScript/Objekte/Object/valueOf

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Wenn die von Object.prototype vererbte Methode valueOf im Kontext eines Objektes aufgerufen wird, dann wird einfach nur eine Referenz auf dieses Objekt zurückgegeben. Wird valueOf hingegen im Kontext eines primitiven Wertes aufgerufen, dann wird abhängig vom Datentyp des Wertes entweder eine Typumwandlung durchgeführt oder ein Fehler geworfen.


Syntax

Object.prototype.valueOf( )


Attribute
Writable true
Enumerable false
Configurable true


Prototyp


Eigenschaften


Bedeutung

Die Methode valueOf führt mit dem Wert ihrer Kontextvariable this intern die abstrakte Operation ToObject durch, nach deren Regeln ein primitiver Wert in ein spezifisches Objekt umgewandelt wird, sofern der Wert nicht vom Datentyp Null oder Undefined ist. Wenn das Argument der Operation allerdings kein primitiver Wert sondern eine Referenz auf ein Objekt ist, dann findet keine Umwandlung statt, sondern es wird lediglich die Referenz auf das Objekt zurückgegeben. Der Rückgabewert der Operation ToObject ist zugleich auch der Rückgabewert von valueOf.


Beispiel
const value = Object.prototype.valueOf( );

console.log(Object.prototype === value); // true


In dem Beispiel oben wird valueOf auf Object.prototype aufgerufen, dessen eigene Methode sie ist. Da es sich bei dem Wert der Eigenschaft prototype des Konstruktors Object natürlich um ein Objekt handelt, wird von der Methode wie gesehen keine Typumwandlung durchgeführt, sondern nur eine Referenz auf Object.prototype zurückgegeben, wie der abschließende Vergleich und die Ausgabe in der Konsole bestätigen.


Beispiel
const object = { };

console.log(object.valueOf( ) === object); // true


Da die Methode valueOf standardmäßig über die Prototypenkette an alle Objekte vererbt wird, kann sie auch auf anderen Objekten direkt aufgerufen werden, sofern das Objekt nur vom allgemeinen Objekt-Typ Object ist und es darüber hinaus keinem spezifischeren Typ angehört. Wird also wie in dem Beispiel oben ein planes Objekt erzeugt, das über keine eigene Methode dieses Namens verfügt, dann kann valueOf auf diesem Objekt aufgerufen werden. Da es sich bei dem Wert in dessen Kontext die Methode ausgeführt wird aber um ein Objekt handelt, wird entsprechend auch hier nur eine Referenz auf das Objekt zurückgegeben.


Beispiel
const wrapper = Object.prototype.valueOf.call('string');

console.log(typeof wrapper); // object

console.log(wrapper instanceof String); // true


Anders sieht es hingegen aus, wenn die Methode valueOf wie in diesem Beispiel im Kontext eines primitiven Wertes aufgerufen wird, was natürlich möglich ist, da valueOf als Funktion die Methoden von Function.prototype erbt. So kann etwa die Methode call verwendet werden, um den Wert zu bestimmen, mit dem die Kontextvariable this von valueOf bei ihrem Aufruf initialisiert wird. Handelt es sich nun bei dem als Argument an call übergebenen Wert um einen primitiven Wert vom Datentyp Symbol, Number, String oder Boolean, dann wird dieser Wert bei der Operation ToObject in ein spezifisches Objekt umgewandelt (Object Wrapper), welches dann von valueOf zurückgegeben wird.


Hinweis:
Bezogen auf die genannten primitiven Datentypen würde übrigens dasselbe Resultat erzielt, wenn man sie dem Konstruktor Object bei dessen Aufruf als Argument übergibt, denn auch hierbei wird intern die abstrakte Operation ToObject ausgeführt, weshalb darüber hinaus auch von Object in dem Fall, dass beim Aufruf ein Objekt als Argument übergeben wird, nur eine Referenz auf dieses Objekt zurückgegeben wird.


Da für primitiven Werte vom Datentyp Null oder Undefined kein eingebauter Konstruktor existiert, welcher für diese Werte einen Object Wrapper erzeugen könnte, wird bei einem Aufruf von valueOf im Kontext dieser Werte ein Typfehler geworfen, der unbehandelt das Programm terminiert.


Beispiel
console.log({ }.valueOf.call(null)); // Type Error

console.log({ }.valueOf.call(undefined)); // Type Error


Bezogen auf das Beispiel oben ist übrigens anzumerken, dass die explizite Übergabe des Wertes undefined im Prinzip überflüssig ist, da Parameter, für die beim Funktionsaufruf kein Argument übergeben wurde, ohnehin grundsätzlich mit diesem Wert initialisiert werden. Ein Aufruf von call ohne Übergabe eines Arguments würde also ebenfalls eine Ausnahme produzieren.

Spezifischere Methoden

Zwar wird die Methode valueOf wie die anderen Methoden von Object.prototype standardmäßig an alle anderen Objekte vererbt, jedoch wird sie entlang der Prototypenkette durch gleichnamige Methoden verschattet, die in den prototypischen Objekten anderer eingebauter Konstruktoren hinterlegt sind und die eine an den jeweiligen Objekttyp angepasste Funktionalität bereitstellen. Die Methode valueOf von Object.prototype dient gewissermaßen als Fallback für Objekte, die nicht selbst eine solche Methode besitzen oder über einen Prototypen verfügen, der eine solche Methode bereitstellt.


Beispiel
const object = new Number(Infinity);

const value = object.valueOf( );

console.log(`${typeof object}, ${typeof value}`); // object, number


Wird etwa wie in diesem Beispiel die eingebaute Funktion Number als Konstruktor aufgerufen und auf diese Weise ein Wrapper Object erzeugt, welches den als Argument übergebenen Wert nach Ausführung der abstrakten Operation ToNumber in seiner internen Eigenschaft [[NumberData]] kapselt, und dann auf diesem Objekt die Methode valueOf aufgerufen, dann wird bei diesem Aufruf nicht die Methode von Object.prototype referenziert, sondern die gleichnamige Methode von Number.prototype. Im Gegensatz zu der Methode des prototypischen Objektes des Konstruktors Object gibt diese Methode nicht einfach eine Referenz auf das Objekt zurück, sondern statt dessen den in der internen Eigenschaft [[NumberData]] des Instanzobjektes gespeicherten primitiven Wert vom Datentyp Number.


Beispiel
console.log(new Boolean(false).valueOf( )); // false

console.log(true.valueOf === Boolean.prototype.valueOf); // true


Die Methode valueOf kann auch direkt auf einem primitiven Wert aufgerufen werden, da in diesem Fall automatisch ein temporäres Objekt vom korrespondierenden spezifischen Objekttyp erzeugt wird, dass den primitiven Wert umschließt und so den Methodenaufruf ermöglicht, es sei denn es handelt sich bei dem Wert um undefined oder null, für die keine eingebauten Konstruktoren existieren. Wie das Beispiel oben zeigt, wird in solchen Fällen jedoch grundsätzlich die Methode valueOf des Objektes aufgerufen, dass in der Eigenschaft prototype des jeweiligen Konstruktors hinterlegt ist und nicht die Methode von Object.prototype.

Eigene Eigenschaften

Die Methode valueOf verfügt über zwei eigene Eigenschaften mit den Namen length und name. Die Eigenschaft length gibt bei Funktionsobjekten grundsätzlich die Anzahl der benannten Parameter zurück und hat bei valueOf den Wert 0, da für diese Methode keine formalen Parameter definiert sind. Der Wert der Eigenschaft name ist der String valueOf, also der Name der Funktion.


Beispiel
console.log({ }.valueOf.name); // valueOf

console.log({ }.valueOf.length); // 0


Beide Eigenschaften sind schreibgeschützt, können jedoch, weil das Attribut [[Configurable]] den Wert true hat, durch Definition verändert werden. Dies sollte jedoch grundsätzlich unterlassen werden, da die Manipulation von eingebauten Objekten unerwünschte Nebeneffekte bis hin zu schwer zu findenden Programmfehlern verursachen kann. Die einzige Ausnahme, bei der die Veränderung solcher Objekte statthaft ist, ist die Bereitstellung standardkonformer Polyfills.

Weblinks

  • ECMAScript 2017 (7th Edition, ECMA-262 Draft): ToObject
  • ECMAScript 2015 (6th Edition, ECMA-262): ToObject