javascript prototype
Tobias
- javascript
Wie überschreibt man in javascript methoden die nicht mit prototype sondern im constructor erstellt worden sind?
hier mein script:
<script language="javascript">
function con()
{
this.show_1 = function(text)
{
alert("show 1: "+text);
};
}
con.prototype.show_2 = function(text)
{
alert("show 2: "+ text);
}
// nun show 1 neu schreiben:
con.prototype.show_1 = function(text)
{
alert('wie geht das?? ' + text);
};
// nun show 2 neu schreiben:
con.prototype.show_2 = function(text)
{
alert('klar, das geht: ' + text);
};
// neue instance
obj = new con();
</script>
<html>
<a href='javascript:obj.show_1("hallo welt")'>test 1</a>
<a href='javascript:obj.show_2("hallo welt")'>test 2</a>
</html>
danke
Tobias
übrigens, das geht alles auch nicht:
con.constructor.show_1 = function(text)
{
alert('foo');
};
window['con'].constructor.show_1 = function(text)
{
alert('foo');
};
window['con'].show_1 = function(text)
{
alert('foo');
};
con.show_1 = function(text)
{
alert('foo');
};
etc....
komischerweise wirft der browser auch keine error (moz)
hallo Tobias,
übrigens, das geht alles auch nicht:
wieso nicht?, oder genauer:
in welchem zusammenhang "geht alles auch nicht"?
nehmen wir an
function con() {
this.show_1 = function(text) {
alert("show 1: "+text);
};
}
ist eine globale funktion, dann ...
... gilt fuer:
con.constructor.show_1 = function(text) {
alert('foo');
};
alert(con.constructor == Function); // true!
Du erweiterst also das "Function"-objekt des javascript-
sprachkerns um eine methode "show_1"; das ist voellig
korrekt, und niemand kann Dir verbieten, dies nicht zu tun;
... gilt fuer:
window['con'].constructor.show_1 = function(text) {
alert('foo');
};
"window['con']" sowie "con" als auch window.con" sind
identisch, da "con" eine globale funktion ist;
daraus folgt:
Du musst die zuletzt gemachte ausfuehrung nocheinmal lesen ;-)
... gilt fuer:
window['con'].show_1 = function(text) {
alert('foo');
};
sowie fuer:
con.show_1 = function(text) {
alert('foo');
};
"window['con']" sowie "con" als auch window.con" sind
identisch, da "con" eine globale funktion ist;
Du erweiterst also das funktions-objekt "con" um eine
eigenschaft "show_1"; auch dies ist voellig korrekt nur ...
... stellt sich in allen von Dir aufgefuehrten beispielen
die frage: warum tust Du das, was willst Du erreichen?
komischerweise wirft der browser auch keine error (moz)
klar:
der verdaut ja nur, was Du in ihn hineinsteckst, und das
war syntaktisch alles korrekt;
by(t)e by(t)e - peterS. - pseliger@gmx.net
hi peter,
warum tust Du das, was willst Du erreichen?
ich möchte eine methode erweitern die ich nicht kenne. eine art "methode listener":
wenn die methode "blahwahnsin()"; gefeuert wird muss dies in einem script gespeichert werden.
achtung: ich haben eben KEINE eventhandler. die methode könnte ja zb. aus einem setInterval gefeuert werden.
nun meine idee war die methode einfach per string concatination zu erweitern und diese dann wieder neu zu schreiben (überschreiben mit dem neuen stück code im source....)
var method_source = con.prototype.show_1.toString();
// irgend ein regulärer ausdruck welche aus dem string "function(var1, var2)" die parameter parsed.
var args = get_method_arguments(method_source);
// methode neu schreiben mit dem method_listener() drin...
eval('con.prototype.show_1= function('+args+') {method_listener(arguments); '+method_source+' }');
function method_listener(args)
{
// hier speichern
}
dies alles geht jedoch bis jetzt nur wenn die methode show_1 per prototypeing dem constructor hinzugefügt wurde.
--> var method_source = con.prototype.show_1.toString();
nun eben die frage:
ist es möglich an den methode source zu kommen wenn sie im constructor erzeugt wurde.
thx. T.
gruss Tobias,
nun eben die frage:
ist es möglich an den methode source zu kommen wenn sie
im constructor erzeugt wurde.
ja - bsp. folgt:
var Con = function() {
this.show_1 = function(text) {
alert("none prototype method "show_1":\n\n" + arguments.callee);
};
};
Con.prototype.show_1 = function(text) {
alert("prototype method "show_1":\n\n" + arguments.callee);
};
Con.prototype.show_2 = function(text) {
alert("prototype method "show_2":\n\n" + arguments.callee);
};
var obj = new Con();
obj.show_1();
obj.show_2();
var methodName, objMethodStr, prototypeStr;
for (methodName in obj) {
if ((typeof obj[methodName] == "function") && (typeof obj.constructor.prototype[methodName] == "function")) {
objMethodStr = obj[methodName].toString();
prototypeStr = obj.constructor.prototype[methodName].toString();
if (objMethodStr == prototypeStr) { // objekt-methode entspricht der prototypen-methode;
alert(""" + methodName + "" is a prototype method:\n\n" + objMethodStr);
} else { // die ueber den prototypen ererbte methode wurde auf dem objekt ueberschrieben;
alert(""" + methodName + "" is an overwritten prototype method:\n\n" + objMethodStr + "\n\ncode of the original prototype:\n\n" + prototypeStr);
}
}
}
das folgende bsp. greift Deiner naechsten frage vor, indem es auf
einfache weise zwei schon vorhandene funktionen gleichen namens
in eine neue gleichlautende funktion ueberfuehrt - das fuer Dich
wichtige parsen von argumenten konnte ich wegen des zeitdrucks
noch nicht beruecksichtigen - ich bin aber dran, und ein zweiter
antwortteil kommt irgendwann morgen:
var objectFct, prototypeFct;
for (methodName in obj) {
if ((typeof obj[methodName] == "function") && (typeof obj.constructor.prototype[methodName] == "function")) {
objMethodStr = obj[methodName].toString();
prototypeStr = obj.constructor.prototype[methodName].toString();
if (objMethodStr != prototypeStr) { /*
die ueber den prototypen ererbte methode sowie die
ueberschreibende methode werden zusammen in eine
neue methode gepackt; */
objectFct = obj[methodName];
prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function() {
prototypeFct();
objectFct();
};
alert("merge of object function "" + methodName + "" and of prototype method "" + methodName + ""\n\n" + obj[methodName]);
objmethodName; // aufruf des neuen vereinigten funktionsobjektes gleichen namens;
}
}
}
beschaeftige Dich doch bis dahin noch einmal mit
dem prototypischen vererbungskonzept in javascript
sowie mit den objekteigenschaften "constructor" und
"prototype";
bis spaeter - peterS. - pseliger@gmx.net
hallo again Tobias,
im zweiten teil knuepfe ich nahtlos an das letzte bsp. an,
in dem die zwei gleichlautenden methoden in eine neue funktion
gleichen namens gepackt wurden, wobei diesmal die fuer beide
funktionen identischen argumente beruecksichtigt werden;
dies geschieht relativ simpel ueber die jeder funktion zueigene
methode "apply", so dass auf ein parsen der funktions-strings
verzichtet werden kann;
der von mir gewaehlte ansatz, zwei bekannte funktionen in einen
neuen funktions-container zu verpacken, versagt natuerlich erst-
einmal in dem moment, wo funktionen werte zurueckgeben - dafuer
muesste man dem folgenden bsp. noch ein paar kleine erweiterungen
angedeihen lassen;
da ich aber nicht wirklich weiss, was Dir so vorschwebt, und ich
deshalb auch aus bequemlichkeit den ansatz ueber "apply" jedem
anderen, mit komplizierten regulaeren ausdruecken arbeitenden,
vorziehe, musst Du mit folgender loesung vorlieb nehmen:
var Con = function() {
this.show_1 = function(text) {
alert("none prototype method "show_1(text)":\n\ntext: "" + text + """);
};
};
Con.prototype.show_1 = function(text) {
alert("prototype method "show_1(text)":\n\ntext: "" + text + """);
};
Con.prototype.show_2 = function(text) {
alert("prototype method "show_2(text)":\n\ntext: "" + text + """);
};
var obj = new Con();
obj.show_1("proof of show_1");
obj.show_2("proof of show_2");
var methodName, objMethodStr, prototypeStr, objectFct, prototypeFct;
for (methodName in obj) {
if ((typeof obj[methodName] == "function") && (typeof obj.constructor.prototype[methodName] == "function")) {
objMethodStr = obj[methodName].toString();
prototypeStr = obj.constructor.prototype[methodName].toString();
if (objMethodStr != prototypeStr) { /*
die ueber den prototypen ererbte methode sowie die
ueberschreibende methode werden zusammen in eine
neue methode gepackt - argumente(n-namen) werden
beruecksichtigt; */
objectFct = obj[methodName];
prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function() {
prototypeFct.apply(null,arguments);
objectFct.apply(null,arguments);
};
alert("merge of object function "" + methodName + "" and of prototype method "" + methodName + ""\n\n" + obj[methodName]);
obj[methodName]("proof of merge"); // aufruf des neuen vereinigten funktionsobjektes gleichen namens;
}
}
}
die von mir ungepruefte erweiterung fuer "return"-werte
koennte so aussehen:
var ..., ..., returnObj = {};
...
obj[methodName] = function() {
returnObj.protoFctValue = prototypeFct.apply(null,arguments);
returnObj.objectFctValue = objectFct.apply(null,arguments);
if ((typeof returnObj.protoFctValue != "undefined") || (typeof returnObj.objectFctValue != "undefined")) {
return returnObj;
}
};
...
so long - peterS. - pseliger@gmx.net
hi peter,
echt sehr cool! thx a lot!
die neue funktionalität wird aber nur auf das object vererbt dass ich grad parse.
-> var obj = new Con();
-> for (methodName in obj) {.....
oder seh ich das falsch?
wenn nein:
wie vererbe ich die änderung auf alle objekte der klasse "Con"?
oder wie komme ich an all die objekte ran die VORHER erzeugt wurden?
hier mein test case:
// **********************************
var Con = function()
{
this.show_1 = function(text)
{
alert("none prototype method "show_1"");
};
};
Con.prototype.show_2 = function(text)
{
alert("prototype method "show_2"");
};
var obj_old = new Con();
// ab hier "kenn" ich das script
var obj = new Con();
var objectFct, prototypeFct;
for (methodName in obj)
{
if ((typeof obj[methodName] == "function"))
{
if(!obj.constructor.prototype[methodName])
{
objMethodStr = obj[methodName].toString();
Con.prototype.show_1 = function(text)
{
objMethodStr();
};
}
prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function()
{
prototypeFct();
alert("---> saved!");
};
}
}
var obj_new = new Con();
</script>
</head>
<body>
<a href='javascript:obj_old.show_1("test")'>test 1 old</a><br>
<a href='javascript:obj_old.show_2("test")'>test 2 old</a><br>
<a href='javascript:obj.show_1("test")'>test 1</a><br>
<a href='javascript:obj.show_2("test")'>test 2</a><br>
<a href='javascript:obj_new.show_1("test")'>test 1 new</a><br>
<a href='javascript:obj_new.show_2("test")'>test 2 new</a><br>
</body>
</html>
gruss Tobias,
die neue funktionalität wird aber nur auf das object vererbt dass
ich grad parse.
...
-> var obj = new Con();
-> for (methodName in obj) {.....oder seh ich das falsch?
nein, und das dies die einzige moeglichkeit ist, schon geschaffene
"Con"-objekte mit neuer funktionalitaet auszustatten, habe ich auch
gleich bei meiner ersten antwort angedeutet:
https://forum.selfhtml.org/?t=87607&m=521124
Wie überschreibt man in javascript methoden die nicht mit
prototype sondern im constructor erstellt worden sind?ausschliesslich am einzelnen objekt;
wenn nein:
wie vererbe ich die änderung auf alle objekte der klasse "Con"?
indem Du Dir jedes einzelne "Con"-objekt zur brust nimmst und
im sinne der von mir schon beschriebenen beispiele erweiterst;
oder wie komme ich an all die objekte ran die VORHER erzeugt wurden?
bei diesem problem kann ich Dir nicht wirklich helfen;
falls Du die kontrolle beim erzeugen solcher objekte hast,
kannst du deren referenzen ja z.b. im objekt "Con.elements = [];"
speichern;
hier mein test case:
...
// ab hier "kenn" ich das script
...
for (methodName in obj)
{
if ((typeof obj[methodName] == "function"))
{
if(!obj.constructor.prototype[methodName])
{
objMethodStr = obj[methodName].toString();
Con.prototype.show_1 = function(text)
-------------^^^^^^^^^^^^^^^^
dies wirkt sich nur auf noch zu erzeugende "Con"-objekte aus,
denn bei den schon existierenden objekten hat der konstruktor
augenblicklich die gleichlautende prototypen-methode, ueber-
schrieben, falls eine solche existierte;
{
objMethodStr();
};
}prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function()
{
prototypeFct();
alert("---> saved!");
};
}
}var obj_new = new Con();
by(t)e by(t)e - peterS. - pseliger@gmx.net
hi Tobias,
jetzt habe ich mal kurz Dein nachgeschobenes posting ueberflogen
- https://forum.selfhtml.org/?t=87607&m=522162 -
und stelle fest, das Du ja schon im gerade besprochenen grobe
handwerkliche fehler begehst:
// ab hier "kenn" ich das script
nicht wirklich :-(
...
for (methodName in obj)
{
if ((typeof obj[methodName] == "function"))
{
if(!obj.constructor.prototype[methodName])
{
objMethodStr = obj[methodName].toString();
-------------^^^^^^^^^^^^
dies ist ein string...
Con.prototype.show_1 = function(text)
-------------^^^^^^^^^^^^^^^^
dies wirkt sich nur auf noch zu erzeugende "Con"-objekte aus,
denn bei den schon existierenden objekten hat der konstruktor
augenblicklich die gleichlautende prototypen-methode, ueber-
schrieben, falls eine solche existierte;{
objMethodStr();
---------------------------^^
... und keine funktion!
};
}prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function()
{
prototypeFct();
alert("---> saved!");
};
}
}
bitte versuche, alle meine beispiele nocheinmal in ruhe
nachzuvollziehen - wir haben zeit;
so long - peterS. - pseliger@gmx.net
resp.
var objectFct, prototypeFct;
for (methodName in obj)
{
if ((typeof obj[methodName] == "function"))
{
if(!obj.constructor.prototype[methodName])
{
objMethodStr = obj[methodName].toString();
obj.constructor.prototype[methodName] = function(text)
{
objMethodStr();
};
}
prototypeFct = obj.constructor.prototype[methodName];
obj[methodName] = function()
{
// ?? oder --> obj.constructor.prototype[methodName] = function() { ... }
prototypeFct();
alert("---> saved!");
};
}
}
hi Tobias,
das geht total in die hose:
var objectFct, prototypeFct;
for (methodName in obj)
{
if ((typeof obj[methodName] == "function"))
{
if(!obj.constructor.prototype[methodName])
{
objMethodStr = obj[methodName].toString();
----------^^^^^^^^^^^^
dies ist ein string ...
obj.constructor.prototype[methodName] = function(text)
{
objMethodStr();
------------------------^^
..., den Du sicherlich nicht als funktion aufrufen kannst;
};
}prototypeFct = obj.constructor.prototype[methodName];
hier weist Du "prototypeFct" die gerade gemachte fehlerbehaftete
aenderung zu;
obj[methodName] = function()
{
// ?? oder --> obj.constructor.prototype[methodName] = function() { ... }
schon wieder eine aenderung der prototypen-methode??
prototypeFct();
alert("---> saved!");
alert("screwed up")
};
}
}
ok.:
JavaScript ist objektorientiert und entzieht sich den zwaengen
der klassenbasierten vererbung indem es sich des prototypen-
konzepts bedient (pro und kontra sollen hier nicht diskutiert
werden - in dieser sprache ist das so, und in anbetracht ihrer
einsatzgebiete ist deren leichtfuessigkeit und offenheit auch
voellig in ordnung);
die zu jedem objekt gehoerende eigenschaft "prototype" referen-
ziert ein objekt dessen eigenschaften immer auch eigenschaften
desjenigen objektes sind, welches diesen prototypen besitzt,
solange dieses objekt nicht ueber eigene gleichbenannte eigen-
schaften verfuegt;
umgangssprachlich bedeutet das:
beim aufruf einer objekt-eigenschaft, wird zuerst das objekt
nach dieser durchsucht - gibt es eine soche eigenschaft nicht,
wird dessen "prototype"-objekt abgeklappert - ist auch diese
suche erfolglos wird dessen "prototype"-objekt herangezogen usw.
... recht schnell landet man dann beim globalen objekt "Object";
diese vererbungskette nennt man auch "prototype chain";
da es sich bei der eigenschaft "prototype" wie bei allem in
JavaScript um ein objekt handelt, kann diese natuerlich fuer
jedes objekt zu jeder zeit manipuliert werden;
by(t)e by(t)e - peterS. - pseliger@gmx.net
gruss Tobias,
Wie überschreibt man in javascript methoden die nicht mit
prototype sondern im constructor erstellt worden sind?
ausschliesslich am einzelnen objekt;
hier mein script:
...
der anfangsbuchstabe eines konstruktoren-namens darf ohne
weiteres gross geschrieben werden ;-)
function Con() {[your code]}
function con() {
this.show_1 = function(text) {
alert("show 1: "+text);
};
}
con.prototype.show_2 = function(text) {
alert("show 2: "+ text);
};
(^--- semikolon hat gefehlt);
// nun show 1 neu schreiben:
definitiv nein - hier wird ueberhaupt das
erstemal eine funktion "show_1" definiert - warum?:
das in der konstruktorfunktion eine objekt-methode
"show_1" vereinbart wird, interessiert den javascript-
interpreter an dieser stelle ueberhaupt nicht, denn
beim laden eine scripts werden zuersteinmal alle
functionsdefinitionen (vor)kompiliert;
der interpreter stoesst also das erstemal auf eine
objektvariable "show_1", die einen funktions-datentyp
enthaelt und als prototypen-funktion des konstruktors
"con" angelegt ist;
con.prototype.show_1 = function(text) {
alert('wie geht das?? ' + text);
};
ok - das ist geklaert;
// nun show 2 neu schreiben:
oder genauer:
//nun die schon existierende prototypen-funktion "show_2"
//ueberschreiben;
con.prototype.show_2 = function(text) {
alert('klar, das geht: ' + text);
};
// neue instance
besser:
// neues con-objekt
<spitzfindig>
in javascript gibt es kein klassen-konzept also auch keine
"instanzen" - in erster linie gibt es objekte;
funktionen (auch die sind objekte) koennen als konstruktoren
fuer objekte dienen;
</spitzfindig>
obj = new con();
mit dem aufruf von "new con()" wird der konstruktor abgearbeitet;
"obj" verfuegt durch den prototypen seines konstruktors dabei
augenblicklich ueber die zwei methoden "show_1" und "show_2"
(aus: "con.prototype.show_1" bzw. aus "con.prototype.show_2");
doch schon kaum nachmessbar spaeter wird die ueber den prototypen
ererbte methode "show_1" durch den konstruktor direkt auf dem objekt
"obj" ueberschrieben (wegen: "this.show_1") - eine jetzt erneut
folgende anderung "show_1" als prototyp des konstruktors "con" -
bsp.: "con.prototype.show_1 = function(text) {[your new code]};" -
hat keinen einfluss auf das schon existierende objekt "obj", da
selbiges schon ueber eine eigene eigenschaft "show_2" verfuegt, und
demzufolge beim zugriff auf ebendiese nicht in der vererbungs-
hirarchie/"prototype chain" nach einem objekt diesen namens
ausschau gehalten werden muss;
soll "obj.show_1" jetzt doch einen anderen funktions-datentyp
enthalten, muss ihm dieser einfach direkt zugewiesen werden:
obj.show_1 = function() {[your new code]};
by(t)e by(t)e - peterS. - pseliger@gmx.net