Die wahreit um this?
bleicher
- javascript
Grüße,
bei den endlosen versuchen JS zu verstehen, blieb ich diesmal wieder an dem tollen this hängen.
die beste beschreibung die ich fand lautete, this referenzieren den objekt, von dem es in der Methode drin sei.
der logik nach, macht es sinn, dass in
function bla(){
var w=this;
}
w das windows zurückgeben würde. bla, als eigenständige funktion ist eine methode von window.
ABER .-
function foo(){
function bar(){
var w=this;
}
}
bar() ist eine methode von foo(), demnach habe ich erwartet, dass this die foo referenziert. es ist aber immer noch window.
1)was soll das this dann?
2)gibt es saubere wege einfach nur den objekt selbst zu referenzieren, ohne immer den namen auszuschreiben?
MFG
bleicher
Grüße,
bei den endlosen versuchen JS zu verstehen, blieb ich diesmal wieder an dem tollen this hängen.
http://www.peterkropff.de/site/javascript/konstruktor_besonderheiten.htm
Imho eine der besten Seiten zum Thema Javascript überhaupt.
Grüße,
das habe ich ja gerade gelesen - nur erklärt es nicht die logik/system hinter this. im konstruktor referenziert es den objekt, solange es mit new erzeugt wurde, sonst window? dann wiederum scheint auch der andere artikel logisch zu klingeln. in einem objektvent referenziert es ja den objekt.
MFG
bleicher
http://www.peterkropff.de/site/javascript/konstruktor_besonderheiten.htm
Imho eine der besten Seiten zum Thema Javascript überhaupt.
Diese Site kann ich absolut nicht empfehlen. Sie war einmal besser, bis der Autor sie überarbeitet hat. Darunter hat nicht nur der Ton gelitten. Da der Autor JavaScript (z.B. Closures) nicht wirklich verstanden hat, hat er bloß versucht, seinem Ärger Ausdruck zu verleihen und dabei ist ziemlicher Quatsch herausgekommen.
Man sieht es z.B. an der dortigen »globalen Methode«, die selbstverständlich Quatsch ist, weil sie nichts mit OOP/Konstruktoren zu tun hat und es kein Grund gibt, so etwas (innerhalb eines Konstruktors) zu tun.
Das var that = this;
hat er sich abgeschaut, anscheinend ohne es wirklich zu verstehen.
Zitat:
»Wenn man innerhalb einer privaten/globalen/anonymen Methode/Funktion der entsprechenden Konstruktorfunktion mit this arbeitet, so verweist das nicht auf das eigene sondern auf das window-Objekt! Is wahr! Ich schwör, Aaalder! Darum muss man in so einem Fall auch einen Umweg gehen.«
Das ist inhaltlich schlicht falsch und bringt viele Begriffe durcheinander.
Korrekt ist, innerhalb einer lokalen, »privaten« Funktion im Konstruktor (es ist keine Methode im strengen Wortsinne, es gibt keine wirklichen privaten Methoden) hat man keinen Zugriff auf die Instanz, wenn man sie einfach über funktion()
und nicht funktion.call(this)
o.ä. aufruft. Daher kann man im Konstruktor var that = this;
und alle Funktionen darin haben auf that Zugriff, weil sie Closures sind.
»Globale Methoden« gibt es nicht und ob eine Funktion anonym ist oder nicht, ist noch einmal etwas ganz anderes.
Allgemein stiftet diese Doku also eher Verwirrung, schade, denn der ursprüngliche Anspruch des Autors ist zu würdigen.
Mathias
Lieber bleicher,
function foo(){
function bar(){
var w=this;
}
}
ist äquivalent zu
~~~javascript
foo = function () {
bar = function () {
var w = this;
}
}
In beiden Fällen werden foo und bar als "globale Variablen" definiert und in JS sind das Methoden von window.
Jetzt klarer?
Liebe Grüße,
Felix Riesterer.
Grüße,
In beiden Fällen werden foo und bar als "globale Variablen" definiert und in JS sind das Methoden von window.
Jetzt klarer?
nein - das ist jetzt schlimmer geworden - laut dem hier ist es eine private methode...
JETZT bin ich verwirrt...
Liebe Grüße,
Felix Riesterer.
MFG
bleicher
function foo(){
function bar(){
var w=this;
}
}
>
> ist äquivalent zu
>
> ~~~javascript
foo = function () {
> bar = function () {
> var w = this;
> }
> }
Das ist falsch.
In beiden Fällen werden foo und bar als "globale Variablen" definiert und in JS sind das Methoden von window.
Nein.
bar ist eine lokale Funktion.
function bar () {}
ist zu nichts anderem vollständig äquivalent. In puncto Sichtbarkeit ist es äquivalent zu
var bar = function () {};
Mathias
Grüße,
ok, nach dem was ihr angerichtet habt, sollt ihr, als ehrenhafte Leute, mein Hirn heiraten.
gibt es irgendwo vernünftige doku/tut zum thema - scopes, OOP und JS-compatible Beruhigungsmittel? die widersprüche und versuche mahcen mich verrückt.... ich wollte doch nur eine kleine klasse für handgemachte "tabs" :/
MFG
bleicher
Lieber bleicher,
ok, nach dem was ihr angerichtet habt, sollt ihr, als ehrenhafte Leute, mein Hirn heiraten.
bitte verwechsle "ehrenhaft" nicht mit "sinnbefreit".
Liebe Grüße,
Felix Riesterer.
Lieber molily,
vielen Dank für Deine Klarstellungen. Aber eines will mir - auch wenn ich Dir bereitwillig Glauben schenke - nicht einleuchten:
function foo(){
function bar(){
var w=this;
}
}
> >
> > ist äquivalent zu
> >
> > ~~~javascript
foo = function () {
> > bar = function () {
> > var w = this;
> > }
> > }
Wenn man das im "globalen Scope" notiert, dann hat man (Du nennst es "laut Sichtbarkeit") im Wesentlichen dem window-Objekt eine neue Methode spendiert: window.foo - oder nicht?
Mir ist jetzt nicht klar, inwiefern hier keine Äquivalenz besteht. Ist es nur der Umstand, dass "function foo () {}" von der JS Engine anders "verstanden" wird, als "foo = function () {}"? Nach meinem laienhaften Wissen ist letzteres eine Deltafunktion, die einer Variable zugewiesen wird, und ersteres eine Funktionsdeklaration - aber wie genau muss man hier in die Tiefen einer JS-Engine gehen, um "äquivalent" sagen zu können?
bar ist eine lokale Funktion.
Das ist das, was ich an JS nicht besonders mag. Mir leuchtet nicht ein, wozu man eine solche lokale Funktion benötigen wollte. Entweder ich bastle mir eine Variable, in die ich ein Funktionsobjekt (ist das dann eine "Deltafunktion"?) in der Art wie oben schmeiße, oder ich definiere mir eine Methode an ein Objekt. Wozu also eine lokale Funktionsdeklaration? Und warum ist sie dann "lokal" und keine Eigenschaft des window-Objektes?
Analog zu Deinem "laut Sichtbarkeit" müsste ich dann schreiben:
function foo () { function bar () { var w = this; } }
ist laut Sichtbarkeit äquivalent zu
window.foo = function () { var bar = function () { var w = this; }; };
Habe ich das jetzt richtig verstanden?
Liebe Grüße,
Felix Riesterer.
Wenn man das im "globalen Scope" notiert, dann hat man (Du nennst es "laut Sichtbarkeit") im Wesentlichen dem window-Objekt eine neue Methode spendiert: window.foo - oder nicht?
Ja.
Mir ist jetzt nicht klar, inwiefern hier keine Äquivalenz besteht. Ist es nur der Umstand, dass "function foo () {}" von der JS Engine anders "verstanden" wird, als "foo = function () {}"?
Es hat eine andere Bedeutung. function foo () {}
deklariert eine Funktion, foo = function () {};
weist dem Identifier foo
eine Funktion als Wert zu. Je nachdem, ob und wo foo
deklariert wurde, ist der Effekt ein ganz anderer.
Nach meinem laienhaften Wissen ist letzteres eine Deltafunktion, die einer Variable zugewiesen wird,
Den Begriff »Deltafunktion« kenne ich persönlich nicht. In ECMAScript wird das Funktionsausdruck (Function Expression) genannt, allgemein Lambda.
und ersteres eine Funktionsdeklaration - aber wie genau muss man hier in die Tiefen einer JS-Engine gehen, um "äquivalent" sagen zu können?
Bei function foo () {}
vs. foo = function () {}
(ohne var
davor, ohne vorherige Deklaration von foo
) ist der Unterschied ein riesiger. Nämlich der zwischen lokalen und globalen Variablen, da muss man nicht in die Tiefen gehen.
Entweder ich bastle mir eine Variable, in die ich ein Funktionsobjekt (ist das dann eine "Deltafunktion"?) in der Art wie oben schmeiße, oder ich definiere mir eine Methode an ein Objekt.
Wenn man var foo = function () {};
schreibt, wäre es tatsächlich eine »Variable, in die ich ein Funktionsobjekt … schmeiße«. Dagegen ist ja nichts einzuwenden, solange man nicht das var
vergisst.
Wozu also eine lokale Funktionsdeklaration? Und warum ist sie dann "lokal" und keine Eigenschaft des window-Objektes?
Funktionsdeklarationen erzeugenokale Funktionen, es sei denn, sie stehen im obersten Kontext. Das ist erst einmal so definiert und darüber hinaus auch durchaus sinnvoll.
Analog zu Deinem "laut Sichtbarkeit" müsste ich dann schreiben:
function foo () { function bar () { var w = this; } }
ist laut Sichtbarkeit äquivalent zu
window.foo = function () { var bar = function () { var w = this; }; };
Habe ich das jetzt richtig verstanden?
Ja, richtig.
Der Unterschied von function bar () {}
zu var foo = function () {};
ist oft vernachlässigbar. Ein Unterschied ist das Hoisting, siehe https://forum.selfhtml.org/?t=208504&m=1418668. Ein anderer ist, dass die Funktion im zweiten Fall anonym ist.
Douglas Crockford rät von Funktionsdeklarationen per se ab und propagiert, stattdessen var f = function () {};
zu verwenden, damit man sich nicht um Hoisting Gedanken machen muss. Ich finde Hoisting bei Funktionsdeklaration hingegen nützlich, zumal man nicht wirklich um Hoisting herumkommt, da Variablendeklarationen ebenfalls gehoistet werden.
Mathias
Lieber molily,
vielen Dank für Deine Präzisierungen.
Den Begriff »Deltafunktion« kenne ich persönlich nicht. In ECMAScript wird das Funktionsausdruck (Function Expression) genannt, allgemein Lambda.
hehe, es war "irgend so ein griechischer Buchstabe halt". Ja, ich meinte Lambda und nicht Delta.
Ein Unterschied ist das Hoisting [...]
Ich finde Hoisting bei Funktionsdeklaration hingegen nützlich, zumal man nicht wirklich um Hoisting herumkommt, da Variablendeklarationen ebenfalls gehoistet werden.
Hmm. Mal davon abgesehen, dass ich das Prinzip des Hoisting noch nicht ganz begriffen habe (in meinen Basteleien hat es keine offensichtliche Bedeutung), bin ich mir nicht sicher, ob jemand explizit über Hoisting nachdenken muss, wenn er ein Script schreibt. Implizit vielleicht, explizit doch wohl eher nicht? Das zumindest ist wohl der Hintergrund, warum Crockford die Wertzuweisung als Notation vorzieht.
Liebe Grüße,
Felix Riesterer.
Mal davon abgesehen, dass ich das Prinzip des Hoisting noch nicht ganz begriffen habe (in meinen Basteleien hat es keine offensichtliche Bedeutung)
Kurz gesagt, Funktionsdeklarationen werden (in einem Ausführungskontext) zuerst ausgeführt, egal wo sie im Quellcode stehen:
alert(typeof foo); // function
function foo () {}
alert(typeof foo); // function
versus
alert(typeof foo); // undefined
var foo = function () {}
alert(typeof foo); // function
bin ich mir nicht sicher, ob jemand explizit über Hoisting nachdenken muss, wenn er ein Script schreibt.
Wenn man intuitiv davon ausgeht, dass Code von oben nach unten abgearbeitet wird, sodass eine Funktion immer deklariert/notiert sein muss, bevor man sie nutzt, bekommt man in der Regel keine Probleme, auch wenn das bei JavaScript durch das Hoisting nicht wirklich der Fall ist.
Es kann aber, genauso wie Hoisting von Variablendeklarationen, eine Fehlerquelle sein, wenn man funktional programmiert. Beispielsweise kann man Funktionsdeklarationen nicht in if-Anweisungen verschachteln oder sonstwie davon ausgehen, dass die Funktion vor dem Code, der sie deklariert, noch nicht zur Verfügung steht. Das ist bei Funktionsausdrücken, die in einer Variablen gespeichert werden, anders.
Mathias
Lieber molily,
Deine Antwort war wieder einmal ganz klar fachlich hilfreich.
Vielen Dank für Deine Ausführungen. Jetzt verstehe ich Deinen Denkansatz hinter Deinen Empfehlungen besser. Da ich erst langsam vom funktionalen zum objektorientierten Schreiben übergehe (und das nur in JavaScript, in PHP will es mir noch nicht so recht einleuchten), fehlen mir vielleicht noch so manche Betrachtungsweisen, die Du mir einfach längst voraus hast.
Liebe Grüße,
Felix Riesterer.
function foo(){
function bar(){
var w=this;
}
}
>
> bar() ist eine methode von foo()
Nein, bar ist keine Methode von foo. (Eine Methode ist definiert als eine Eigenschaft eines Objektes vom Typ Function.)
Dann wäre es ja eine Methode eines Funktionsobjektes. Das geht natürlich:
~~~javascript
var foo = function () {};
foo.bar = function () { alert(this === foo); };
foo.bar(); // true;
Willst du das wirklich? Wieso? Ich glaube, du suchst etwas ganz anderes.
2)gibt es saubere wege einfach nur den objekt selbst zu referenzieren, ohne immer den namen auszuschreiben?
Ich weiß nicht, was du mit »das Objekt selbst« meinst. Ich vermute, du redest von Konstruktoren, also Funktionen, die mit new aufgerufen werden, sodass »this« darin auf ein neu erzeugtes, leeres Objekt zeigt. Lies dir mal folgendes durch:
http://molily.de/js/organisation-instanzen.html
http://molily.de/js/organisation-verfuegbarkeit.html
Mathias
Grüße,
Willst du das wirklich? Wieso? Ich glaube, du suchst etwas ganz anderes.
zumindest scheint es mir eine gute idee - ich wollte ein objekt mit ein paar methoden erstellen, die auch noch obendrauf als eventHandler verfügbar sein sollten. oder zumidnest eigenschaften von.
//bekommt calsse der divs die als tabs zusammengefasst werden sollen
function tabSet(c){
var targetClass=c;
//klassen für aktive/inaktive tab-schlater/reiter
var activeR="fgReiter";
var inactiveR="bgReiter";
var tabs=document.body.getElementsByClassName(targetClass);
//alle ausblenden
function hidetabs(){
for(i=0;i<tabs.length;i++){
tabs[i].style.display="none";
}
//reiter gleich mit
for(i=0;i<reiter.length;i++){
//activeklasse?weg damit
e.target.classList.toggle(inactiveR);
e.target.classList.toggle(activeR);
}
}
//by ID
this.showTab=function(e){
//bekommt id (expliziter aufruf) oder click-event des reiters
var id;
if(typeof(e)=="string"){
id=e;
for(i=0;i<reiter.length;i++){
if(reiter[i].dataset["target"]==id){
reiter[i].classList.toggle(inactiveR);
reiter[i].classList.toggle(activeR);
}
}
}else{
id=e.target.dataset["target"];
//reiter wurde angeklikt - aktive klasse zuweisen
e.target.classList.toggle(inactiveR);
e.target.classList.toggle(activeR);
}
gid(id).style.display="block";
}
//erstellt die UL mit den "reitern"
function makeList(){
var tabList=document.createElement("ul"),li;
//die über class angewählten tabs ollten über data-title ihren titel
//mitteilen und eine id haben, die dem titel entspricht
for(i=0;i<tabs.length,t=tabs[i];i++){
li=html.li(t.dataset["title"]);
li.addEventListener("click",
function(e){
hidetabs();
showTab(e);
//PROBLEMSTELLE
//zugriff auf die variablen activeR/inactiveR notwendig,um dem aktiven tab richtige klasse zu geben
}
,false);
li.dataset["target"]=t.id;
li.classList.add(inactiveR);
tabList.appendChild(li);
}
tabList.id=targetClass+"TabList";
tabList.className="tabSetReiterleiste";
return tabList;
}
var reiter=makeList();
//die reiterliste als erste in das elternelement der tabs einfügen
tabs[0].parentNode.insertBefore(reiter, tabs[0].parentNode.firstChild);
//ersten tab+reiter zeigen
hidetabs();
this.showTab(tabs[0].id);
}
http://molily.de/js/organisation-instanzen.html
http://molily.de/js/organisation-verfuegbarkeit.html
Mathias
danke -
ich konzentriere mich drauf- die kropffseite scheint ein paar misscverständnisse zu zugen.
MFG
bleicher
//PROBLEMSTELLE
//zugriff auf die variablen activeR/inactiveR notwendig,um dem aktiven tab richtige klasse zu geben
Du kannst an dieser Stelle einfach über »activeR« und »inactiveR« auf die Variablen activeR und inactiveR zugreifen. Genauso, wie du es auch überall anders tust. Was ist das Problem?
Mathias
Grüße,
//PROBLEMSTELLE
//zugriff auf die variablen activeR/inactiveR notwendig,um dem aktiven tab richtige klasse zu gebenDu kannst an dieser Stelle einfach über »activeR« und »inactiveR« auf die Variablen activeR und inactiveR zugreifen. Genauso, wie du es auch überall anders tust. Was ist das Problem?
Mathias
ich versuche
1)die methoden nicht global uz machen - der ganze sinn war ja, dass ich den globalen namensraum nicht vollkake, aber mit this.shoTabs definierte methode ist aus der ananonymen eventhandler funktion nicht aufrufbar - hier mal was ich da sehe (und ich habe 0 Ahnung, was die bereiche 1-2 im scope sollen... :(
MFG
bleicher
Hallo,
1. Bitte ordne deine Gedanken und gehe strukturiert vor.
2. Versuche sie geordnet ins Forum zu bringen.
3. Lies die Artikel, die ich dir gegeben habe.
4. Beschreibe gezielt, was du tun willst und was nicht funktioniert hat.
1)die methoden nicht global uz machen - der ganze sinn war ja, dass ich den globalen namensraum nicht vollkake, aber mit this.shoTabs definierte methode ist aus der ananonymen eventhandler funktion nicht aufrufbar - hier mal was ich da sehe (und ich habe 0 Ahnung, was die bereiche 1-2 im scope sollen... :(
Du versuchst offenbar die Instanzmethode showTab aufzurufen. Okay. Das geht dort nicht über this.showTab, korrekt. Wie du darauf zugreifst, darüber handeln die Texte, die ich dir gegeben habe. Eine Lösung ist, im Scope des Konstruktors eine Variable anzulegen, die auf die Instanz verweist. Z.B. var instance = this;
Diese Variable steht in den verschachtelten Funktionen verfügbar und ist anstelle von this nutzbar.
»1-Bereich« ist einfach der erste Scope in der Scope Chain, d.h. der Scope der gegenwärtigen Funktion selbst. »2-Bereich« der zweite, also der darüber liegende der äußeren Funktion usw. Schließlich kommt der globale Scope.
Mathias
Grüße,
danke - ich habe mich glaube in der "revealing pattern" version versucht - ich frage mich aber, ob das so ok ist - einfach nur den DOMelementen eigenschaften anzuhängen?
// (targetElement class, tablist class))
function tabSet(c,RC){
this.tabs=document.getElementsByClassName(c);
this.targetClass=c;
this.reiterClass=RC;
//für jeden tab eine menupunkt
var tabList=document.createElement("ul"),li;
//das verstecken der tabs un schalten der classen von reitern sit eine funktion des listenElements
tabList.hideTabs=function(){
var n, t;
for(n in this.childNodes){
t=this.childNodes[n];
if(t.connectedTab){
if(t.classList.contains("active")){
t.classList.remove("active");
}
t.connectedTab.style.display="none";
}
}
}
//durch alle tabs gehen - zugehöriges element ist eigenschaft des listenelements "connectedTab"
for(i=0;i<this.tabs.length;i++){
li=html.li(this.tabs[i].dataset["title"]);
li.connectedTab=this.tabs[i];
li.addEventListener("click",function(e){
this.parentNode.hideTabs();
this.connectedTab.style.display="block";
if(!this.classList.contains("active")){
this.classList.add("active");
}
},false);
tabList.appendChild(li);
}
//liste einfügen
tabList.classList.add(this.reiterClass);
this.tabs[0].parentNode.insertBefore(tabList, this.tabs[0].parentNode.firstChild);
tabList.hideTabs();
//erstes tab aktivieren, simulieren klick auf 1en reiter
tabList.firstChild.click();
}
MFG
bleicher
Funktion != Objekt
Funktion != Methode
Spiel mal damit rum, das dürfte Dich aufklären:
<html>
<head>
<title>Ärger mit this</title>
<script type="text/javascript">
alert('Viewport: ' + this.innerHeight + 'px * ' + this.innerWidth+ 'px');
function zeigeFarbe(objekt) {
alert(objekt.style.color);
}
</script>
</head>
<body>
<p style="color:red" onclick="zeigeFarbe(this)">Klick hier!</p>
<p style="color:blue" onclick="zeigeFarbe(this)">Klick hier!</p>
</body>
</html>
Lieber Fred Furunkelstein 2012,
Funktion != Objekt
Eine Funktion ist doch ein Objekt, ein Funktionsobjekt! Aber ein Funktionsobjekt ist etwas anderes als new Object()
. Letzteres wirst Du wohl gemeint haben.
Funktion != Methode
Wenn Du eine Lambda-Funktion von einer Methode eines Objektes unterscheiden willst, dann hast Du sicherlich Recht, hier zwischen "Methode eines Objekts" und "ein Funktionsobjekt" zu unterscheiden. Ob das aber in JS als generelle Nomenklatur gilt, weiß ich nicht.
Spiel mal damit rum, das dürfte Dich aufklären:
[...]
alert('Viewport: ' + this.innerHeight + 'px * ' + this.innerWidth+ 'px');
function zeigeFarbe(objekt) {
alert(objekt.style.color);
}
Da verstehe ich nicht, was Dein Code-Beispiel zeigen soll. Insbesondere das Thread-Thema "this" wird hier nicht wirklich untersucht.
In Deinem Beispiel wird während des Seitenaufbaus ein alert ausgegeben, der irgendwelche Eigenschaften des window-Objekts ausgibt ("this" im globalen Scope zeigt auf window).
Dann notierst Du eine Funktionsdeklaration, die ein Funktionsobjekt erzeugt, welches den Namen "zeigeFarbe" erhält und dem window-Objekt als gleichnamige Methode zugewiesen wird. Man kann also window.zeigeFarbe(o) nutzen, wobei o eine Referenz auf ein (HTML-Element-)Objekt sein muss, welches eine Eigenschaft "style" haben muss, da sonst ein Fehler auftreten wird. Existiert eine Eigenschaft "style", und ist sie ein Objekt, welches eine Eigenschaft "color" hat, dann kann der Wert von "color" ausgegeben werden, ansonsten sieht man im alert "undefined".
Nochmals: Wie wolltest Du mit Deinem Code-Beispiel Deine beiden Eingangsbehauptungen ("Funktion != Objekt" und "Funktion != Methode") stützen?
Liebe Grüße,
Felix Riesterer.
--
ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
Hallo Felix!
Nochmals: Wie wolltest Du mit Deinem Code-Beispiel Deine beiden Eingangsbehauptungen ("Funktion != Objekt" und "Funktion != Methode") stützen?
Nein, ich wollte mit dem Beispiel eigentlich auf den "scope" hinaus. Das Beispiel war wohl schlecht.
Fred