Oop in javascript

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Hallo

Ik ben wat aan het uitproberen met Object Oriented Programming in javascript, stukje code:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function Slideshow(imElement)
{
    //initialize the member variables for this instance
    this.element = imElement;
    this.images = 0;
    this.imgNow = 0;

    //intitialize the member function references
    Slideshow.prototype.AjaxRequestImages = AjaxRequestImages;
    Slideshow.prototype.SetFirst = SetFirst;
    
    //define Slideshow methods
    function AjaxRequestImages()
    {
        var xmlhttp;
        
        //Create XMLHttpRequest object 
        if(window.XMLHttpRequest)
        {//code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }   
        else
        {//code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        
        //Wait for response
        xmlhttp.onreadystatechange = function()
        {
            if(xmlhttp.readyState==4 && xmlhttp.status==200)
            {//when readyState = 4 and status = 200 response is ready
                this.images = xmlhttp.responseText.split('|');
            }
        }   
        
        //Send request to the server
        xmlhttp.open("GET","slideshow.php",true);
        xmlhttp.send();
    }
    
    function Show()
    {
        alert(this.images);
    }
}

var ssObj;

function InitSlideshow()
{
    ssObj = new Slideshow("ssImage");
    ssObj.AjaxRequestImages();
    ssObj.Show();
}


Even toelichten: De functie InitSlideshow wordt uitgevoerd bij een onload event. De functie maakt eerst een object van Slideshow en roept dan de functie AjaxRequestImages() op. Deze functie hoeft enkel variable this.images te voorzien van image sources bv.: "foto1.jpg" "foto2.jpg" . Met functie Show() wil ik dit zichtbaar maken via een alert maar hier loopt het fout. this.images blijkt nog steeds 0 te zijn (initialisatie waarde).
Plaats ik de alert onder this.images = xmlhttp.responseText.split('|'); krijg ik wel het resultaat dat ik verwacht.
Momenteel zie ik niet wat ik fout doe, hopelijk kunnen jullie me verder helpen alvast bedankt.

Acties:
  • 0 Henk 'm!

  • smesjz
  • Registratie: Juli 2002
  • Niet online
imgages vs images om mee te beginnen

Acties:
  • 0 Henk 'm!

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

SetFirst() moet Show() zijn in dit voorbeeld denk ik?

Ajax is asynchroon, de onreadystatechange wordt uitgevoerd op het moment dat de data geladen is. Je hebt dan ook een timingsprobleem als je dat direct na de ajax-call aanroept.

Je kunt dit dan ook beter event based oplossen, zoals je zelf al probeerde: in de onreadystatechange.

Acties:
  • 0 Henk 'm!

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Bedankt

SetFirst() moet inderdaad Show() zijn werd aangepast ook imgages is gecorrigeerd.

Timingprobleem zou inderdaad wel eens het probleem kunnen zijn, ga dit eens proberen op te lossen.

Acties:
  • 0 Henk 'm!

  • Klaasvaak
  • Registratie: Maart 2010
  • Laatst online: 23-09 22:25
Je moet je prototype ook niet binnenin de constructor functie opbouwen. Nu wordt je prototype elke keer dat je een nieuwe instance maakt opnieuw gecreeerdt, terwijl dat maar een keer nodig is.
JavaScript:
1
2
3
4
5
6
function Slideshow() {...};

(function(proto) {
 function show() {...};
 proto.show = show;
}(Slideshow.prototype));

Acties:
  • 0 Henk 'm!

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Ik heb het probleem opgelost, de oorzaak was ook niet timing maar het volgende:

JavaScript:
1
2
3
4
5
6
7
8
//Wait for response
xmlhttp.onreadystatechange = function()
{
     if(xmlhttp.readyState==4 && xmlhttp.status==200)
     {//when readyState = 4 and status = 200 response is ready
          this.images =  xmlhttp.responseText.split('|');
     }
}    


this verwijst hier niet naar een instantie van mijn object maar naar een XmlHttpRequest object, this.images = xmlhttp.responseText.split('|'); is gewoon declaratie en initialisatie van een nieuwe variabele.
Dit is de oplossing:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//define Slideshow methods
    function AjaxRequestImages()
    {
        var xmlhttp;
        var self = this;
        
        //Create XMLHttpRequest object 
        if(window.XMLHttpRequest)
        {//code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }   
        else
        {//code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        
        //Wait for response
        xmlhttp.onreadystatechange = function()
        {
            if(xmlhttp.readyState==4 && xmlhttp.status==200)
            {//when readyState = 4 and status = 200 response is ready
                self.images = xmlhttp.responseText.split('|');
                document.getElementById("ssImage").src = self.images[0];
            }
        }   
        
        //Send request to the server
        xmlhttp.open("GET","slideshow.php",true);
        xmlhttp.send();
    }


De referentie van mijn Slideshow object stop ik in een variable self en gebruik deze dan binnen de if-lus.
Het probleem heb ik gevonden door mijn script te debuggen met Firebug een add-on van firefox.

@Klaasvaak: ik begrijp niet echt wat je bedoelt, dat stukje code is wat onduidelijk voor mij.

Acties:
  • 0 Henk 'm!

  • noes
  • Registratie: Augustus 2006
  • Niet online

noes

gek op benzine.

Wat klaas bedoelde is dat dit

JavaScript:
1
2
3
//intitialize the member function references
    Slideshow.prototype.AjaxRequestImages = AjaxRequestImages;
    Slideshow.prototype.SetFirst = SetFirst; 


Onnodig is in je object. Hier breidt je je object uit dmv prototyping, iets wat je in staat stelt een object aan te passen ná creatie.

Persoonlijk vind ik het makkelijker om dit te doen:

JavaScript:
1
2
    this.AjaxRequestImages = function(){ ... };
    this.SetFirst= function(){ ... };


Zo zijn bovenstaande methodes ook vanaf buiten beschikbaar.

--

Tevens, als je nu een wat langere pingtijd hebt naar je server zal je functie alsnog falen: je this.images kan gewoon leeg blijven: je doet geen check oid. In je onreadystatechange event kan je de functie Show gewoon aanroepen indien je ajax succesvol is.

K54/R1250RS | K48/K1600GT | E61/550i


Acties:
  • 0 Henk 'm!

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Bedankt

Dus ik zou beter nog een check inbouwen of this.images de correcte data bevat vooraleer ik er mee ga werken. Lijkt mij inderdaad logisch.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Beide bovengenoemde OO patronen maken eigenlijk dezelfde fout: ze stellen het definiëren van methods uit totdat de constructor gedraaid wordt.

In het patroon van Steve04 worden de methods in de constructor op het prototype aangemaakt, terwijl in het patroon van noes de methods op het object zelf gedefinieerd worden en niet op het prototype. In beide gevallen leidt dit tot overmatig geheugengebruik.

Daarnaast zal in geen van beide gevallen de prototype chain correct zijn, wat belangrijk is als je met de instanceof operator wilt gaan werken i.c.m. inheritance en polymorphism

Heel ruw opgezet is de correcte manier om een class te definiëren als volgt:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
window.namespace.ClassName = (function(){
  
  var ctor = function(paramA, paramB) {
    this.propertyA = paramA;
    this.propertyB = paramB;

    window.namespace.SuperClassName.apply( this, arguments );
  };

  ctor.prototype = new window.namespace.SuperClassName();
  ctor.prototype.constructor = ctor;

  ctor.prototype.showA = function() {
    show( this.propertyA );
  }
  
  ctor.prototype.showB = function() {
    show( this.propertyB );
  }

  // private
  function show( msg ) {
    alert( msg );
  }

  return ctor;
})();


Vaak is het makkelijker om dit patroon te implementeren m.b.v. een factory method. Dat is wat netter.

[ Voor 3% gewijzigd door R4gnax op 08-09-2011 22:15 . Reden: Voorbeeld bijgewerkt met opmerkingen van Blues ]


Acties:
  • 0 Henk 'm!

Verwijderd

R4gnax op regel 10 en 14 bedoel je this.propertyA en this.propertyB?

Verder mis ik nog een SuperClassName.apply(this, arguments) ergens voor de inheritance.

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Verwijderd schreef op woensdag 07 september 2011 @ 14:21:
R4gnax op regel 10 en 14 bedoel je this.propertyA en this.propertyB?

Verder mis ik nog een SuperClassName.apply(this, arguments) ergens voor de inheritance.
Je hebt helemaal gelijk. Heb het maar even snel bijgewerkt. Dat krijg je als je zoiets even zonder nadenken in 5min probeert uit te typen. :P

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Ik heb een paar vraagjes over die code omdat ik er weinig op terug vindt op het net.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
window.namespace.ClassName = (function(){
  
  var ctor = function(paramA, paramB) {
    this.propertyA = paramA;
    this.propertyB = paramB;

    window.namespace.SuperClassName.apply( arguments );
 
    ctor.prototype = new window.namespace.SuperClassName(); 
   
    .......
 
    return ctor;
  };


Het eerste wat je doet is waarschijnlijk een nieuwe klasse definiëren binnen een namespace. In mijn geval zou dit zoiets worden:
JavaScript:
1
window.namespace.Slideshow = (function(){.....}; ?


Daarna definieer je binnen de klasse een constructor zodat je later objecten kunt van maken?

Volgende zaken begrijp ik niet echt:
JavaScript:
1
2
window.namespace.SuperClassName.apply( arguments ); 
ctor.prototype = new window.namespace.SuperClassName();

  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Volgende zaken begrijp ik niet echt:
Wat begrijp je er niet aan dan? Bepaalde keywords? Het concept? Scoping?

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Wel wat de functie er van is: bv SuperClassName.apply(arguments) waarop wijst dit ?

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Steve04 schreef op donderdag 08 september 2011 @ 14:41:
Wel wat de functie er van is: bv SuperClassName.apply(arguments) waarop wijst dit ?
SuperClassName was in mijn voorbeeld de base class. De apply functie voert de constructor uit van de base class en geeft deze dezelfde argumenten mee via de arguments collectie. (Het moet trouwens zijn .apply(this, arguments) , zie ik. Zal dat nog even herstellen.)

  • Steve04
  • Registratie: September 2011
  • Laatst online: 06-08 07:48
Dus als ik het goed begrijp gebruik je dit
JavaScript:
1
window.namespace.SuperClassName.apply( this, arguments );


om er voor te zorgen dat de afgeleide klasse (ClassName) naast zijn specifieke parameters ook deze van de base klasse overerft?

JavaScript:
1
ctor.prototype = new window.namespace.SuperClassName(); 


Hiermee zou dus de afgeleide klasse over alle functies van de base klasse moeten beschikken?

Alvast bedankt voor de uitleg.

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Dat is inderdaad ongeveer het effect.

Lees anders ook eens : https://developer.mozilla...bject-Oriented_JavaScript

Daar staan wat meer concrete voorbeelden.
Pagina: 1