SitePoint Sponsor

User Tag List

Results 1 to 13 of 13
  1. #1
    SitePoint Guru
    Join Date
    Nov 2005
    Location
    Midwest
    Posts
    777
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Private Function Calling Public Function – OO JavaScript

    Hello

    I am trying to learn more about coding object oriented JavaScript. Here is a situation that has me confused.

    Code:
    <html>
    <head>
    
    <script language="JavaScript">
    
    function test()
    {
       test = new classExample();
       test.publicFunction();
    }
    
    function classExample()
    {
       this.publicFunction = function()
       {
          alert("publicFunction");
          alert( this );
          this.secondPublicFunction();
          privateFunction();
       }
    
       privateFunction = function()
       {
          alert("privateFunction");
          secondPrivateFunction();
          alert( this );
          this.secondPublicFunction();
       }
       
       secondPrivateFunction = function()
       {
          alert("secondPrivateFunction");   
       }
       
       this.secondPublicFunction = function()
       {
          alert("secondPublicFunction");
       }
    }
    
    </script>
    </head>
    
    <body>
    
    <a href="javascript: test()">Test</a>
    
    </body>
    </html>
    In the example I am trying to have a function within a class (what I am calling a JavaScript class) call another function. I am using this. to make functions public. Without putting the this. to me means it is private.

    The situation I am trying to get help in understanding is that within a class, I thought all functions could call each other. In this example, that is not true. Once in the privateFunction, I can not call any other public function. I can call other private functions but I get an error stating “this.secondPublicFunction is not a function” if I call a public function.

    Does anyone know why privateFunction() can not call secondPublicFunction()? I also find it odd that when I do an alert from the private function, this is referring to Window. When I do an alert from the public function, this refers to the Object, which is what I expected.

    Thanks in advance for your time.

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Because Javascipt isn't a class based language and it doesn't have access controls. Thus you can't transfer your knowledge from traditional class based languages directly onto Javascript.
    What you call a private function is in fact a local function. Because of the scoping rules, it can sort of do the same things as a private method in other languages, but it's not quite the same. The tricky part is the keyword this. In Javascript, it doesn't refer to the owner of the function, as you might expect. Instead it refers to the object, it was called on. To understand this, consider that functions are variables and you can assign a variable multiple times. So you can easily (And indeed often will) assign the same function to multiple objects.
    When you're calling privateFunction, you're not using the object dispatch syntax (Eg. this.privateFunction()), so this isn't bound to what you expect -- Instead it's bound to the default value (window). If you replace alert with console.log and install Firebug, you can see this:
    Code:
    >>> function test() { test = new classExample(); test.publicFunction(); } function classExample()...
    publicFunction
    Object
    secondPublicFunction
    privateFunction
    secondPrivateFunction
    Window showthread.php
    Now, to achieve what you want, you can save a reference to this in a variable, which is accessible to the scope of the "private" methods. this is rebound on each function call, but other variables aren't, so you can do this:
    Code:
    test = function()
    {
       test = new classExample();
       test.publicFunction();
    }
    
    classExample = function()
    {
      var self = this; // at the time of creation, this refers to the created object
      this.publicFunction = function()
      {
         console.log("publicFunction");
         console.log( this );
         this.secondPublicFunction();
         privateFunction();
      }
    
      var privateFunction = function()
      {
         console.log("privateFunction");
         secondPrivateFunction();
         console.log( self );
         self.secondPublicFunction();
      }
      
      var secondPrivateFunction = function()
      {
         console.log("secondPrivateFunction");   
      }
      
      this.secondPublicFunction = function()
      {
         console.log("secondPublicFunction");
      }
    }
    test();
    You can use any name for the variable, but it's convention to use self.

    Also note that when you're creating local functions, you should put the var keyword in front of the variable declaration. Otherwise, the function is created in the global scope and thus isn't that private at all.
    Eg. these two are the same:
    Code:
      secondPrivateFunction = function()
      {
         console.log("secondPrivateFunction");   
      }
    and
    Code:
      window.secondPrivateFunction = function()
      {
         console.log("secondPrivateFunction");   
      }
    Last edited by kyberfabrikken; Nov 27, 2007 at 06:55. Reason: Slightly confusing type. cope -> scope

  3. #3
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks kyberfabrikken that was an amazinf explaination.

  4. #4
    SitePoint Guru
    Join Date
    Nov 2005
    Location
    Midwest
    Posts
    777
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree, this was an amazing explanation. Thank you for the time.

    As a follow up to your post, for ease of coding, should someone just always use self?

    For example, this.secondPublicFunction() from this.publicFunction() could be called using self.secondPublicFunction(). This way, when someone is coding, they always use self. Is this a good habit to get into?

  5. #5
    SitePoint Guru
    Join Date
    Nov 2005
    Location
    Midwest
    Posts
    777
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A second question about self… I did some research and it says self can be used to reference the global object for the current document, regardless of what scope your script is running in. So it seems self is kind of like a reserved word since it already has functionality for it. With this said, is it a good habit to override self in ClassExample? I know you said a different variable name can be used but I am curious why a standard is being used to override self by using the variable name self.

  6. #6
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TryingToLearn View Post
    As a follow up to your post, for ease of coding, should someone just always use self?

    For example, this.secondPublicFunction() from this.publicFunction() could be called using self.secondPublicFunction(). This way, when someone is coding, they always use self. Is this a good habit to get into?
    From within the constructor, it doesn't matter if you use self or this. I'd probably use this in that case, but I don't think I'm consistent on it.
    Assigning functions to objects explicitly, isn't the most used pattern anyway. If you're going to create multiple instances, you should consider putting them on the constructors prototype, instead of explicitly assigning them. Eg.:
    Code:
    classExample.prototype.publicFunction = function() {
       console.log("publicFunction");
       console.log(this);
       this.secondPublicFunction();
    }
    Of course, you can't access the object's private methods, using this and all the methods will be public. It makes a big difference in performance though. A function on a prototype is a single variable. When you assign it explicitly, you create a separate variable, and a separate scope closure each time. This takes up time and memory, making your script slow.

    Quote Originally Posted by TryingToLearn View Post
    A second question about self… I did some research and it says self can be used to reference the global object for the current document, regardless of what scope your script is running in.
    Yes, it's basically a synonym for window. Javascript has a ridiculous amount of reserved words, even though they aren't used. It may seem like a bad idea to use self this way, but it's very common to do, so I wouldn't worry. Besides, you aren't overriding the global variable self -- You're shadowing for it, with a new, local variable.

  7. #7
    Google Engineer polvero's Avatar
    Join Date
    Oct 2003
    Location
    Mountain View
    Posts
    567
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The best approach to encapsulating private methods and instance methods is to use the classic module approach. It looks like this:

    Code:
    function ConstructorFunc(name) {
      this.name = name;
    }
    ConstructorFunc.prototype = function() {
      function privateMethod() {
    
      }
      function anotherPrivateMethod() {
    
      }
      var secret = 3;
      return {
        publicMethod: function() {
    
        },
        anotherPublicMethod: function() {
          alert(this.name);
        },
        privledgedMethod: function() {
          // giving away secrets
          alert(secret);
        }
      };
    }();
    And for most folks coming from class based languages, this will have a higher appeal. Run time mutational inheritance usually screws with peoples mind (the fact that I can extend a object (class) at any given time). The module approach keeps everything encapsulated, all tucked away in one spot.
    Cheers.

    On a side note, hey look, 500 posts... and it only took 4 years.

  8. #8
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's nifty, but wouldn't it make var secret shared between all instances of ConstructorFunc?

    Edit: Yeah, it does.
    Code:
    function ConstructorFunc() {}
    ConstructorFunc.prototype = function() {
      var secret = 3;
      return {
        setSecret: function(value) {
          secret = value;
        },
        getSecret: function() {
          return secret;
        }
      };
    }();
    
    var x = new ConstructorFunc();
    x.setSecret(42);
    var y = new ConstructorFunc();
    y.setSecret(11);
    [x.getSecret(), y.getSecret()];
    Code:
    [11, 11]

  9. #9
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You can also try apply() (or call) methods
    http://developer.mozilla.org/en/docs...Function:apply

    Code:
    function classExample() {
       this.publicFunction = function()
       {
          alert( this.x );
          privateFunction.apply(this);
       }
    
       var privateFunction = function()
       {
          alert( this.x );
         
       }
    }
    
    test = new classExample();
    test.x = 123;
    test.publicFunction();
    "this" in "privateFunction" is what you expect it to be.

  10. #10
    Google Engineer polvero's Avatar
    Join Date
    Oct 2003
    Location
    Mountain View
    Posts
    567
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's nifty, but wouldn't it make var secret shared between all instances of ConstructorFunc?

    Edit: Yeah, it does.
    Ya. I know. Cool, huh?

  11. #11
    SitePoint Guru
    Join Date
    Nov 2005
    Location
    Midwest
    Posts
    777
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the replies. I have learned a lot from them.

    I do have a question about prototype. Based on these examples, prototype sets a value across all instances of a function. Why would I want to do this? If I create a separate instance of something, don’t I want to keep it separated from other instances?

    I also have another question. Private functions can be written in multiple ways within an object. Here are two examples.

    Code:
    function ConstructorFunc() {}
    
    ConstructorFunc = function()
    {
       var privateMethod = function()
       {
           doSomething…
       }
    
       function anotherPrivateMethod()
       {
           doSomething…
       }
    }
    To me privateMethod and anotherPrivateMethod are exactly the same except the function decaration is written a little different. I’m I correct here… there is no difference between privateMethod and anotherPrivate method except the function declaration is written differently? They are both private and they are both tied to the ConstructorFunc and not Window?

  12. #12
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TryingToLearn View Post
    I do have a question about prototype. Based on these examples, prototype sets a value across all instances of a function. Why would I want to do this? If I create a separate instance of something, don’t I want to keep it separated from other instances?
    Exactly. You don't want that.

    So the conclusion would be, that if you want private properties, you need to create them for each instance. Because of this, I prefer to do without access control. You can use convention, in lieu -- It's a common practice to name private members with a preceding underscore. The access isn't enforced, so it's a weaker contract, but that'll do in most cases.

    Quote Originally Posted by TryingToLearn View Post
    To me privateMethod and anotherPrivateMethod are exactly the same except the function decaration is written a little different. I’m I correct here… there is no difference between privateMethod and anotherPrivate method except the function declaration is written differently? They are both private and they are both tied to the ConstructorFunc and not Window?
    You're right. I think that some browsers (all?), will allow you to use the function before its declaration, if you use the function name() syntax, rather then name = function(). I'm not entirely sure -- I may remember wrongly about that.
    Otherwise, the only technical difference is, that you can do this:
    Code:
    foo.bar = function() {
    }
    ... but not this:
    Code:
    function foo.bar() {
    }
    I prefer to always use the assignment-syntax, because it more explicitly shows what is happening inside the Javascript runtime engine. Also, for consistency, so that I only use one syntax.

  13. #13
    Google Engineer polvero's Avatar
    Join Date
    Oct 2003
    Location
    Mountain View
    Posts
    567
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The only problem you'll have with the varying function declarations is that if you plan on using a function using the assignment operator - it must be assigned before you use it. For example:

    Code:
    doFoo();
    var doFoo = function() {
      alert('hello world');
    };
    // doFoo is undefined
    
    // however
    doBar();
    function doBar() {
      alert('hello world');
    }
    // alert's 'hello world'
    If you don't want private variables, assigning functions to the prototype is most definitely your best option. Making separate copies of the same function just takes up memory. Therefore when a function is shared accoss all instances, you'll get faster applications. Like kyberfabrikken mentioned, it's a common convention in JavaScript just to use an underscore as a prefix/suffix.

    Code:
    ConstructorFunc function() {
      this._secret = 3;
      this.anotherSecret_ = 'ninja';
    }
    However nothing stops the implementor from accessing these properties.


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
  •