Von Instanz direkt auf Eigenschaft zugreifen
T-Rex
- javascript
Hallo,
Hab da eine Klasse gebaut, welche unter anderem die Eigenschaft obj besitzt. Diese Eigenschaft wird Außerhalb der Klasse ziemlich oft gebraucht. Ich muss ständig mit .obj drauf zugreifen.
function Klasse()
{
this.obj = "was auch immer"
}
var Instanz = new Klasse;
alert(Instanz.obj); -> ausgabe "was auch immer";
Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz .obj auf die Eigenschaft zugreifen kann. Sprich eine Weiterleitung in der Klasse.
alert(Instanz); -> ausgabe "was auch immer";
Gruß
T-Rex
Hi,
var Instanz = new Klasse;
alert(Instanz.obj); -> ausgabe "was auch immer";Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz .obj auf die Eigenschaft zugreifen kann. Sprich eine Weiterleitung in der Klasse.
alert(Instanz); -> ausgabe "was auch immer";
Das sollte machbar sein, wenn du dem Objekt eine eigene toString-Methode spendierst, die den Inhalt von obj zurueckgibt.
Den Wert darueber auch zu setzen, duerfte allerdings nicht moeglich sein - aber das wuerde das OO-Prinzip ja dann auch eher pervertieren, wenn du im Code ein Objekt ueberschreibst, um effektiv lediglich eine Eigenschaft von diesem zu aendern.
MfG ChrisB
Den Wert darueber auch zu setzen, duerfte allerdings nicht moeglich sein - aber das wuerde das OO-Prinzip ja dann auch eher pervertieren, wenn du im Code ein Objekt ueberschreibst, um effektiv lediglich eine Eigenschaft von diesem zu aendern.
In C++ kann man den Zuweisungsoperator überladen, mir wird das immer als tolles Feature verkauft.
Hi Chris,
den Wert setzen will ich ja nicht. Dennoch hab ich das mit dem toString Methode nciht ganz verstanden?!.
Kannst du da vielleicht bitte ein Beispiel geben? Wäre echt Klasse.
Danke
T-Rex
Hi,
den Wert setzen will ich ja nicht. Dennoch hab ich das mit dem toString Methode nciht ganz verstanden?!.
Kannst du da vielleicht bitte ein Beispiel geben?
Wenn du ein JavaScript-Objekt in einem String-Kontext verwendest (also es bspw. per alert ausgeben laesst), welches aber nicht vom Typ String ist - dann muss ja irgendwie festgelegt werden, wie die Ausgabe dann lauten soll.
Dafuer haben solche Objekte eine toString-Methode, die implizit aufgerufen wird, wenn du das Objekt in einem Kontext benutzt, wo nur ein String gebraucht werden kann.
alert(document.body) beispielsweise wird dir "[object HTMLBodyElement]" (oder sowas aehnliches, je nach Browser - meine Beispielausgaben sind vom Opera) ausgeben. Es handelt sich also um ein Element vom Typ HTMLBodyElement - das laesst sich nicht direkt in einem Stringkontext "ausgeben", also liefert dessen toString-Methode eben jenen Text stattdessen.
alert(document.body.toString()) liefert das gleiche - das waere der direkte Aufruf. Bei der obigen Schreibweise wird die Methode auch aufgerufen, nur eben implizit.
Wenn wir mal dein Objekt aus deinem Eingangsposting nehmen,
function Klasse() {
this.obj = "was auch immer"
}
var Instanz = new Klasse;
alert(Instanz.obj);
Wenn du jetzt aber deinem Objekt eine eigene Methode mit dem speziellen Namen toString verpasst - dann wird diese aufgerufen, sobald das Objekt irgendwo in einen Stringkontext ueberfuehrt werden muss. Und damit hast du die Kontrolle darueber, wie diese Ausgabe dann lautet - also kannst du sie bspw. auch den Wert der Objekt-Eigenschaft obj zurueckgeben lassen:
function Klasse() {
this.obj = "was auch immer";
this.toString = function() {
return this.obj;
};
}
var instance = new Klasse();
alert(instance);
(Diese Methode muss natuerlich "public" sein, also mit dem Keyword this deklariert werden, denn sie muss ja von ausserhalb des Objektes aufrufbar sein.)
MfG ChrisB
Hi Chris,
vielen Dank für deine ausführliche Beschreibung. Leider funktioniert es bei mir nicht, da this.obj ein Object ist (denk ich).
function Klasse() {
this.obj = document.getElementById('Knoten');
this.toString = function() {
return this.obj;
};
}
var instance = new Klasse();
alert(instance); <-- gibt einfach nix zurück
das alert gibt einfach nix aus. Weder true noch false.
Dementsprechend kann ich mit instance.offsetWidth (z.B.) auch nicht auf den Knoten zugreifen :(.
Gruß
T-Rex
Hi,
vielen Dank für deine ausführliche Beschreibung. Leider funktioniert es bei mir nicht, da this.obj ein Object ist (denk ich).
function Klasse() {
this.obj = document.getElementById('Knoten');
Ja, das waere dann wieder ein HTMLElementObject - die JavaScript-Objektrepraesentation eines Knotens im DOM des HTM-Dokumentes.
this.toString = function() {
return this.obj;
};
}var instance = new Klasse();
alert(instance); <-- gibt einfach nix zurück
Das da "gar nichts" als Ausgabe kommt, haette ich zwar nicht erwartet - aber es ist vielleicht auch nicht verwunderlich.
Na dem impliziten Aufruf einer toString-Methode erwartet der JS-Interpreter wohl, dass er jetzt auch einen String vorliegen haben muesste, der sich ausgeben liesse - das ist aber nicht der Fall, weil deine toString-Methode keinen String geliefert hat, sondern wiederum ein Object. Jetzt noch mal dessen toString-Methode aufzurufen, sollte zwar wieder [object HTMLElementObject] (o.ae.) bringen - aber diesen impliziten Aufruf macht der Interpreter jetzt wohl nicht mehr, weil er ja annimmt, er muesse bereits einen String vorliegen haben.
Dementsprechend kann ich mit instance.offsetWidth (z.B.) auch nicht auf den Knoten zugreifen :(.
Das kann sowieso nicht funktionieren.
Hier liegt kein Kontext vor, in dem es notwendig waere, instance in einen String umzuwandeln - also wuerde auch eine toString-Methode des Objektes gar nicht erst aufgerufen.
Damit greifst du also lediglich auf eine Eigenschaft offsetWidth der Instanz von "Klasse" zu, die diese aber nicht besitzt - das kann also hoechstens undefined ergeben.
Irgendwie habe ich immer noch den Eindruck, dass du die Objektorientierung hier zu pervertieren versuchst.
Wenn dein Element instance in einer Eigenschaft die Referenz auf ein weiteres Objekt gespeichert hat - dann nutze auch diese Eigenschaft zum Zugriff auf das Objekt, und ggf. zu ihm gehoerige weitere Eigenschaften.
Warum versuchst du hier auf Teufel komm raus irgendwelche "Shortcuts" einzufuehren - die der gaengigen Vorgehensweise in der OO absolut widersprechen?
MfG ChrisB
»[HTMLElement]e mit zusätzlichem Verhalten ausstatten«
oder
»Funktoren als Vehicle für abstrakte Datentypen in JavaScript«
hallo again T-Rex,
wenn Du die direkte referenzierung von [HTMLElement]en beibehalten,
ihnen aber trotzdem zusaetzliches verhalten mit auf den weg geben
willst, solltest Du genau dies mit deinem code abbilden.
Du moechtest keinen zu instanziierenden wrapper schreiben, sondern
die spezialisierung eines abstrakten datentyps - nennen wir die
benoetigte implementierung eines solchen konstrukts einfach mal
»Behavior« oder »Interface« oder eben auch »Trait«.
aus der sicht von JavaScript handelt es sich bei der loesung um
eine funktion, die wie ein konstruktor aufgebaut ist, aber nicht
als solcher ueber den »new« operator aufgerufen wird.
solche funktionen - wir geben ihnen mal den konzeptionellen namen
»Funktor« bzw. »Functor« - werden immer im kontext schon vorhandener
objekte ausgefuehrt und bereichern diese objekte dann um die im
funktor vereinbarte prozesslogik und/oder datenstruktur.
ein moeglicher beispielhafter loesungsansatz für Dein problem sieht
dann so aus und verlangt wie immer der ueberpreufung in der [jconsole]:
// [document.getCurrentStyle] - [http://www.pseliger.de/jsExtendedApi/jsApi.document.getCurrentStyle.dev.js]
document.getCurrentStyle = (function (nodeObj/*[HTMLElement|Node]*/, cssScheme/*[string|String](css-attributes written according to html-css-scheme)*/) {var isElementNode=(function(obj){return(obj&&(typeof obj.nodeName==="string")&&(typeof obj.nodeType==="number")&&(obj.nodeType===1));});var notDefined;var regXHyphenSepatator=(/\-(\w)/g);var replaceWithUppercase=(function(str,$1){return $1.toUpperCase();});var convertHtmlIntoJsCssScheme=(function(cssScheme){cssScheme=cssScheme.replace(regXHyphenSepatator,replaceWithUppercase);return(((cssScheme=="float")||(cssScheme=="cssFloat"))?("styleFloat"):(cssScheme));});var fct=(function(){return notDefined;});if(document.defaultView&&document.defaultView.getComputedStyle){fct=(function(nodeObj,cssScheme){var currStyle;if(isElementNode(nodeObj)){cssScheme=String(cssScheme);cssScheme=(((cssScheme=="cssFloat")||(cssScheme=="styleFloat"))?("float"):(cssScheme));currStyle=document.defaultView.getComputedStyle(nodeObj,"").getPropertyValue(cssScheme);}return((currStyle==="")?(notDefined):(currStyle));});}else if(document.documentElement&&document.documentElement.currentStyle){fct=(function(nodeObj,cssScheme){var currStyle;if(isElementNode(nodeObj)){currStyle=nodeObj.currentStyle[convertHtmlIntoJsCssScheme(String(cssScheme))];}return currStyle;});}return fct;})();
// [document.getElmPosAbsolute] - [http://www.pseliger.de/jsExtendedApi/jsApi.bundles.DOM.getters.dev.js]
document.getElmPosAbsolute = (function (elm) {var x=0,y=0;if(elm&&elm.offsetParent){x=elm.offsetLeft;y=elm.offsetTop;elm=elm.offsetParent;while(elm){x=x+elm.offsetLeft;y=y+elm.offsetTop;elm=elm.offsetParent;}}return{"left":x,"top":y};});
var HTMLElementBehavior = (function () { // der funktor [[HTMLElementBehavior]]
this.getCurrentStyle = (function (cssScheme) {
return document.getCurrentStyle(this, cssScheme);
});
this.getPosAbsolute = (function () {
return document.getElmPosAbsolute(this);
});
});
var obj = document.getElementsByTagName("div")["output"];
HTMLElementBehavior.call(obj); // [obj] das neue verhalten *beibringen*.
print("obj.getCurrentStyle(\"background-color\") : " + obj.getCurrentStyle("background-color"));
print("obj.getPosAbsolute().left : " + obj.getPosAbsolute().left);
print("obj.getPosAbsolute().top : " + obj.getPosAbsolute().top);
links die zur am heutigen tag ausformulierten erkenntnis fuehrten:
so long - peterS. - pseliger@gmx.net
gruss T - Rex,
...
Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz
.obj auf die Eigenschaft zugreifen kann. ...
alert(Instanz); -> ausgabe "was auch immer";
...
folgende machbarkeitsstudie mal bitte mit *copy und paste*
der [jconsole] zukommen lassen.
var MyOwnTypesConstructor = (function (typesValue) {
this.valueOf = (function () {
return typesValue;
});
this.toString = (function () {
return String(typesValue);
});
});
var myOwnType = new MyOwnTypesConstructor(23);
print("\n");
print("myOwnType + 19 : " + (myOwnType + 19)); // 42
print("myOwnType + \"19\" : " + (myOwnType + "19")); // "2319"
print("\n");
print("myOwnType : " + myOwnType); // 23
print("\n");
print("(typeof myOwnType) : " + (typeof myOwnType)); // "object"
print("(typeof (myOwnType + 0)) : " + (typeof (myOwnType + 0))); // "number"
print("(typeof (myOwnType + \"\")) : " + (typeof (myOwnType + ""))); // "string"
weiterfuehrende links zu dieser thematik:
so long - peterS. - pseliger@gmx.net
[code lang=javascript]var MyOwnTypesConstructor = (function (typesValue) {
this.valueOf = (function () {
return typesValue;
});
this.toString = (function () {return String(typesValue);
});
});[/quote]
Hat aber auch Nachteile:
[code lang=javascript]var o1=new MyOwnTypesConstructor(0);
var o2=new MyOwnTypesConstructor(0);
print("o1==o2: "+(o1==o2)); // false
print("o1==0: "+(o1==0)); // true
print("o2==0: "+(o2==0)); // true[/quote]
D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.
gruss Timo,
Hat aber auch Nachteile:
...
D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.
...
keineswegs ...
var MyOwnTypesConstructor = (function (typesValue) {
this.valueOf = (function () {
return typesValue;
});
this.toString = (function () {
return String(typesValue);
});
});
var o1 = new MyOwnTypesConstructor(0);
var o2 = new MyOwnTypesConstructor(0);
print("o1 == o2: " + (o1 == o2)); // false
print("o1 == 0 : " + (o1 == 0)); // true
print("o2 == 0 : " + (o2 == 0)); // true
/*
> var o1=new MyOwnTypesConstructor(0);
> var o2=new MyOwnTypesConstructor(0);
>
> print("o1==o2: "+(o1==o2)); // false
> print("o1==0: "+(o1==0)); // true
> print("o2==0: "+(o2==0)); // true
>
> D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.
ja und? - dass ergebnis ist keineswegs ueberraschend.
es werden auch keinerlei regeln verletzt; schliesslich
arbeiten wir hier mit objekten und nicht mit primitiven
typen bzw. werten.
die beim vergleichen zum tragen kommende automatische
typwandlung arbeitet JavaScript-regelkonform - siehe auch:
*/
print("(o1 === o2) ? " + (o1 === o2)); // false
print("(o1 === 0) ? " + (o1 === 0)); // false
print("(o2 === 0) ? " + (o2 === 0)); // false
var num1 = new Number(0);
var num2 = new Number(0);
print("(num1 == num2) ? " + (num1 == num2)); // false ... objektreferenzen
print("(num1 == 0) ? " + (num1 == 0)); // true ... typwandlung durch wert
print("(num2 == 0) ? " + (num2 == 0)); // true ... typwandlung durch wert
print("(num1 === num2) ? " + (num1 === num2)); // false ... objektreferenzen
print("(num1 === 0) ? " + (num1 === 0)); // false ... typwandlung ausgeschlossen
print("(num2 === 0) ? " + (num2 === 0)); // false ... typwandlung ausgeschlossen
mein fazit:
bei der dem OP aufgezeigten loesung handelt es sich um eine
nach ECMA 262 mustergueltige implementierung eigener objekttypen.
so long - peterS. - pseliger@gmx.net