Avatar billede r_ibsen Nybegynder
14. marts 2004 - 15:24 Der er 6 kommentarer

Virkefeltsregler / miljø i js. Overskrivning af onchange-funktion

Hej,

jeg har nogle problemer med at få kaldt en funktion i min superklasse med det rigtige miljø.
Først en generel beskrivelse af problemet: jeg har en klasse (eller hvad det nu hedder i js) Obj1 som indeholder et array observers samt en funktion notify(), som benytter observers. Desuden har jeg et nedarvet objekt Obj2 som indeholder en reference select til en select box. Når select ændrer sig (onchange) vil jeg bl.a. gerne kalde notify(), således at det er notify() hørende til det objekt der har referencen select, der kaldes.
Jeg har i øjeblikket:

<html>
<head>
<script>
function Obj1(){
  var self = this;
  self.observers = new Array();

  this.attach = function(n){
  self.observers.push(n);
  };

  this.notify = function(){
    //Should do something to all elements in observers
    //but just print message for now
    alert("observers has " + self.observers.length + " elements.");
  }

}

function Obj2(_select){
  var select = _select;

  select.onchange = function(){alert("Noget andet kode"); this.notify();};
  //select.onchange = this.notify;
}

Obj2.prototype = new Obj1;
Obj2.prototype.constructor = Obj1;

</script>
</head>
<body>
<form name=theForm>
<select name=theSelect>
<option value="">Entry1
<option value="">Entry2
</select>
</form>
</body>
<script>
var master = new Obj2(document.theForm.theSelect);
master.attach(1); master.attach(2);
</script>
</html>

Når jeg vælger noget nyt i theSelect går det galt ved kaldet this.notify(); Jeg får en fejl der siger at objektet ikke understøtter metoden. Er det fordi this i stedet for at referere til master, kommer til at referere til theSelect (i strid med hvad jeg ønsker)?
Hvis jeg ændrer tildelingen til select.onchange = this.notify; virker tingene som de skal - jeg får kaldt notify() korrekt og den skriver korrekt at observers har to elementer. Men det er ikke helt godt nok, jeg vil gerne kunne udføre noget kode før kaldet til notify().
På forhånd mange tak.
Avatar billede olebole Juniormester
14. marts 2004 - 20:03 #1
<ole>

Noget tyder på, du er vandt til mere 'snavsede' sprog, som VBScript  :)
Til en start bør du angive dit scriptsprog i dit scripttag.
Dernæst bør du undgå at give variabler reserverede ord (eller ord, som har en specifik betydning i JavaScript) som navne ... 'self' og 'select' bør du nok ikke anvende.
Ligeledes bør du nok afslutte dine options. Det er ikke påkrævet, men hvis du ønsker din kode skal være fremtidssikret, bør du afslutte dem. Åbne tags har ikke ret lang tid igen.

Så til dit aktuelle problem: Du er inde på det rigtige. 'this' i en callback-funktion refererer ikke til JS-objektet, men til HTML-elementet.
Prøv denne kode, så kan du sikkert se forskellen:

<script type="text/JavaScript">
function Obj1() {
    var oMe = this;
    oMe.observers = new Array();
   
    this.attach = function(n) {
        oMe.observers.push(n);
    };
    this.className = "noget";
    this.notify = function() {
        //Should do something to all elements in observers
        //but just print message for now
        alert("observers has " + oMe.observers.length + " elements.");
    }
}
function Obj2(_select) {
    var oMe = this;
    var mySelect = _select;
    mySelect.onchange = function(){alert("Antal options i din select: "+this.options.length); alert("Noget andet kode"); oMe.notify();};
    //select.onchange = this.notify;
}
Obj2.prototype = new Obj1;
Obj2.prototype.constructor = Obj1;
</script>

Variablen 'oMe' refererer til selve JS-objektet ... du var faktisk selv inde på det med: 'var self = this;' i din første constructor  :)

/mvh
</bole>
Avatar billede olebole Juniormester
14. marts 2004 - 20:07 #2
PS: this.className = "noget"; skal du bare glemme ... det var noget, jeg ville bruge til at eksemplificere - men valgte en anden vej  :)
/mvh
Avatar billede r_ibsen Nybegynder
14. marts 2004 - 21:04 #3
Nej, problemet er ikke, at jeg er vant til VBScript - problemet er at jeg slet ikke er vant til scriptsprog, så alt der her med løs typning og underlige scope-regler og få fejlmeddelelser forvirrer mig en del ;-)
Tak for rådene - de gjorde mirakler for min kode :-)
Jeg var ikke klar over at self og select var reserverede ord.
Jeg tillader mig lige at stille et tillægsspørgsmål:
Hvorfor bruger du this.foo = function(){//} når du laver funktioner, men oMe.bar = 3.14; når du tildeler til variable? Er det fordi this virker fint i constructoren, men ikke i de indlejrede funktioner?
Igen, mange tak for hjælpen.

Mvh Rune
Avatar billede r_ibsen Nybegynder
14. marts 2004 - 21:06 #4
Hmmm, kan se at du også bruger oMe.observers = new Array() ude i constructoren. ??
Avatar billede olebole Juniormester
14. marts 2004 - 21:28 #5
Oooops .... 'oMe.observers = new Array();' er en fejl! Det skal være 'this' og ikke 'oMe'.
At det ikke betyder noget, da 'oMe' er sat til at referere til constructor'en, friholder mig ikke - logikken mangler  :)

Som du har opdaget, refererer 'this' ikke til objektet, hvis det bruges i en event-handler eller callback-funktion.
Her opretter man derimod en variabel, som i oprettelses-øjeblikket peger på objektet. Den vil så også pege på objektet, når event'en udløses.
Prøv, om dette eksempel kan hjælpe til en tydeliggørelse:

<html>
<head>
<script type="text/JavaScript">
function MyObjConstructor(ID) {
    var oMe = this;
    this.elm = document.getElementById(ID);
    this.className = "Min Klasse";
    this.elm.onclick = function() {
        this.style.backgroundColor = "red";
        this.style.fontWeight = "bold";
        this.innerHTML = oMe.className;
    }
    return this;
}

window.onload = function() {
    var myObj = new MyObjConstructor("ib");
}
</script>
</head>
<body>

<div id="ib">Blabla blablabla</div>

</body>
</html>
Avatar billede r_ibsen Nybegynder
14. marts 2004 - 22:57 #6
Mange tak, nu er jeg med.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester