SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Member
    Join Date
    Sep 2004
    Location
    San Francisco, CA
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    This doesn't seem like good practice

    I've been struggling with a scope issue for days... I read this article http://www.sitepoint.com/blogs/2004/...ript-closures/ and I finally got it to work by using var self = this. The problem is that doesn't seem like a practical solution. My confusion is that there are so many ways to write objects and handle scope that I'm not sure how to approach the problem anymore! So I'm looking for an explanation/solution to this problem to hopefully avoid future conflicts. All help is obviously appreciated. This is a simple breakdown of the code...

    function AJAX() {
    if(window.ActiveXObject) {
    this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    } else {
    this.xmlHttp = new XMLHttpRequest();
    }

    this.checkStatus = function(request) {
    dbug.printToDisplay('readyState = '+this.xmlHttp.readyState);
    }

    this.send = function(method, url){
    var self = this; // this works but just doesn't seem practical
    this.xmlHttp.open(method, url, true);
    this.xmlHttp.onreadystatechange = function() {
    self.checkStatus(); // without setting self = this i get a variety of problems using call, apply, arguments.callee, parent, self, this, and anonymous function etc, etc. I just need guidance!!
    }
    this.xmlHttp.send(null);
    }
    }

  2. #2
    SitePoint Addict jtrelfa's Avatar
    Join Date
    Oct 2004
    Location
    Troy, Mi
    Posts
    231
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by richmulhern
    Code:
    function AJAX() {
    	if(window.ActiveXObject) {
    		this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");	
    	} else {
    		this.xmlHttp = new XMLHttpRequest();
    	}
    		
    	this.checkStatus = function(request) {
    		dbug.printToDisplay('readyState = '+this.xmlHttp.readyState);
    	}
    	
    	this.send = function(method, url){	
    		var self = this;   // this works but just doesn't seem practical
    		this.xmlHttp.open(method, url, true);
    		this.xmlHttp.onreadystatechange =  function() {
    			self.checkStatus();   // without setting self = this i get a variety of problems using call, apply, arguments.callee, parent, self, this, and anonymous function etc, etc. I just need guidance!!
    		}
    		this.xmlHttp.send(null);
    	}
    }
    While I can appreciate that you're trying to simplify an AJAX request, why not use one of the pre-built libraries out there? They are free to use and do nothing but make your life easier. I like the prototype.js library. Here's an example of retrieving some data using AJAX to update a div with an id of 'results':
    Code:
    var options = {
        method:get,
        parameters:"param1=123&param2=456"
        }
    new Ajax.Updater('results','server_script.php',options);
    That's it! Prototype handles all the work of cross-browser compatibility, etc. You can even specify a div for 'sucess' and 'failure' so that it will put the data in a different location depending on how the XHR pans out.

    There are a ton of other helper functions that prototype provides; and it's bundled with a bunch of other libraries that can give your app some zing without being too bulky. (Scriptaculous is one of them)

    I dunno if I helped..?

    Jon

  3. #3
    SitePoint Member
    Join Date
    Sep 2004
    Location
    San Francisco, CA
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey Jon,

    I appreciate the suggestion. I understand there are a lot of libraries, I'm even familiar with prototype as we use it at work. Libraries go against exactly what I am trying to do here though. I want to know why this works this way and what the best way to resolve it. If I were to pick up a library I'd be learning the libraries ways, and not the guts of JavaScript. Plus, who's to say my next job will use prototype too? I'd rather have a good understanding of why something does or does not work in JavaScript so next time I see it I can approach it without the crutch of a library.

  4. #4
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Rich,

    The onreadystatechange property is assigned a reference to a function. When that function is called this no longer references the AJAX object, but the self variable does properly reference the AJAX object, and is in scope because of the lexical closure.

    edit...

    Additionally, when self.checkStatus() is called this now references the AJAX object because of self.checkStatus().

  5. #5
    SitePoint Member
    Join Date
    Sep 2004
    Location
    San Francisco, CA
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike, thanks for your answer. I understand why I the code works, var self = this sets self to the Object and that by scope is passed down to all functions in that method. That just seems like a hackish way to go about it though.

    What I am looking for is an explanation as to why it has to be done this way, if it has to be done this way or the most efficent way of doing it.

  6. #6
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What I am looking for is an explanation as to why it has to be done this way
    That's what I was trying to do... but I'm not the best at these things.

    Perhaps it is instructive to see what happens when checkStatus() is a private function:

    Code:
    function AJAX()
    {
      // Public
    
      this.publicCheckStatus = function(request) {
        window.status += 'pub:' + this.xmlHttp.readyState + ', ';
      }
    
      this.send = function(method, url) {
        this.xmlHttp.open(method, url, true);
        this.xmlHttp.onreadystatechange = onReadyStateChange;
        this.xmlHttp.send(null);
      }
    
      // Private
    
      var self = this;
    
      function onReadyStateChange() {
        privateCheckStatus();
        self.publicCheckStatus();
      }
    
      function privateCheckStatus() {
        window.status += 'pri:' + self.xmlHttp.readyState + ', ';
      }
    
      // Constructor
    
      if (window.ActiveXObject) {
        this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 
      } else {
        this.xmlHttp = new XMLHttpRequest();
      }
    } // end AJAX object prototype
    The self variable is still needed in order to reference the AJAX object because when privateCheckStatus() is called, this is not pointing to the AJAX object.

    Perhaps I am misunderstanding the question.

  7. #7
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    No, it doesn't have to be done this way. If the xmlHttp variable were global, then self would not be needed.

  8. #8
    SitePoint Member
    Join Date
    Sep 2004
    Location
    San Francisco, CA
    Posts
    11
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmm thanks Mike. That helps alot. I guess I will keep the self in my code but I still feel like theres got to be anoter way to access this without setting self to this or making the request public. :/


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •