Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 2 of 2
  1. #1
    Regular Coder
    Join Date
    Oct 2009
    Posts
    189
    Thanks
    38
    Thanked 3 Times in 3 Posts

    private methods in javascript question

    Hey all,

    In the book "programmer's reference", the author uses an example of a private method in javascript:
    Code:
    var StringBuilder = (function() {
    var privateArray = new Array();
    function privateAppend(str) {
    privateArray[privateArray.length] = str;
    }
    return {
    add: function(str) {
    privateAppend(str);
    },
    value: function() {
    return privateArray.join(“”);
    }
    }
    })();
    // First we show that the string is empty
    document.write(“Our String: “ + StringBuilder.value() + “ < br / > ”); // “Our String: “
    StringBuilder.add(“Super”);
    StringBuilder.add(“Cala”);
    StringBuilder.add(“Frajalistic”);
    // Now we display the finished concatenated string
    document.write(“Our String: “ + StringBuilder.value() + “ < br / > ”); // “Our String:
    SuperCalaFrajalistic”
    He says the () at the end of the StringBuilder() function executes it immediately. So I assume that this means the StringBuilder() function executes before the StringBuilder.add() functions called later on. What I don't understand is when the StringBuilder() function is called, it goes line by line in the code block, so how come it doesn't return undefined parameter "str" error: function privateAppend(str). No parameter has been passed into str at this point, so I don't get why it doesn't return an error here.
    Also he says "the last statement in the function is a return , which returns an object containing two closures ( add() and value() )". When it returns these two methods, isn't argument str in add(str) equal to null, given that nothing has been passed into it yet, yet it doesn't return an error?

  • #2
    Senior Coder
    Join Date
    Jul 2005
    Location
    New York, NY
    Posts
    1,084
    Thanks
    4
    Thanked 19 Times in 19 Posts
    Let's indent the code.
    Code:
    var StringBuilder = (function() {
        var privateArray = new Array();
        function privateAppend(str) {
            privateArray[privateArray.length] = str;
        }
    
        return {
            add: function(str) {
                privateAppend(str);
            },
            value: function() {
                return privateArray.join(“”);
            }
        }
    })();
    
    // First we show that the string is empty
    document.write(“Our String: “ + StringBuilder.value() + “ < br / > ”); // “Our String: “
    
    StringBuilder.add(“Super”);
    StringBuilder.add(“Cala”);
    StringBuilder.add(“Frajalistic”);
    
    // Now we display the finished concatenated string
    document.write(“Our String: “ + StringBuilder.value() + “ < br / > ”); // “Our String:
    SuperCalaFrajalistic”
    So, look at the StringBuilder variable. It's a function that gets executed upon definition, similar to this:
    Code:
    function alert_x() { alert('x'); }();
    This just alerts 'x'. So what does the StringBuilder function do when it's executed? Well, first it defines to local variables: privateArray and privateAppend. The first is an empty array, the second is a function. privateAppend is not called, it is merely defined.

    Then, it returns an object. You may recognize {} from JSON (JavaScript Object Notation). So the last statement in the main function returns an object. In that object, there are 2 functions defined: add and value. These functions are not called, they are merely defined.

    So what's the point of all this weirdness.

    Well, let's take a simpler example.
    Code:
    function alert_x() {
      var x = 'x';
      alert(x);
    }();
    
    alert(x);
    The first section defines and calls a function called alert_x which alerts 'x'. The last line alerts the variable x which is undefined. But the alert_x function defines the x variable! Ok, so what's going on here? Nothing weird, you're probably familiar with local variables.

    What you're probably not familiar enough with are the concept of functions as variables AND the concept of closures. Defining a local variable puts a name:value pair into the current context. That context is an object, known as a closure. Standard garbage collection states that if nothing references an object, delete it, but if something references it, leave it there.

    Well, every object in javascript contains a reference to it's defining context. It's just that most people use only one context ever: the global context.
    Code:
    var x = 'x';
    function alert_x() {
      alert(x);
    }();
    Nothing wrong with this code right? The variable x is global, so every function can access it. Well, go one layer deeper.
    Code:
    var x = 'x';
    function one_layer() {
      var y = 'y';
      function alert_y() {
        alert(y);
      }();
    }
    
    one_layer(); // alerts 'y'
    alert_y(); // undefined function "alert_y"
    In this code, we defined a function that defined a local variable AND a local function. That inner local function had access to the local variables that were defined in the same context as itself. That is the essence of a closure. Now, how do you avoid the error on the last line?
    Code:
    var x = 'x';
    function one_layer() {
      var y = 'y';
      return function() {
        alert(y);
      }
    }
    
    var my_func = one_layer(); // returns a nameless function
    my_func(); // alerts 'y'
    So, now I'm calling the inner function outside of the scope of the defining function. We already saw that local variables aren't accessible once the function has run, so why doesn't my_func() throw an error? Why is it able to resolve the variable y? Because my_func has a reference to it's defining scope, which contains a name:value pair for the variable y. One more example to drive it home.
    Code:
    var x = 'x';
    var y = 'GLOBAL SCOPE'
    function one_layer() {
      var y = 'LOCAL SCOPE';
      return function() {
        alert(y);
      }
    }
    
    var my_func = one_layer(); // returns a nameless function
    my_func(); // alerts 'LOCAL SCOPE'
    There is a scope chain. Whenever a variable is encountered during execution, it must be resolved. If your inside a function, the first place it looks is the local scope. The next place it looks is whatever the local scope says is its parent scope. Usually, that's the global scope, which is why you can defined vars all over the place and access them in any function. But if you define a function inside another function AND you get the inner function out (a closure) then the parent scope is the defining scope, so all the variables defined locally by the parent function are available to the child closure, but no one else!

    These are the mechanisms used to create public and private members in javascript objects. In your example, add() and value() are not called until the end. They are defined by StringBuilder() but not executed. The object returned by StringBuilder holds a reference to the scope it was defined in, that scope contains the two variables labeled "private".

  • Users who have thanked Beagle for this post:

    johnmerlino (07-07-2010)


  •  

    Tags for this Thread

    Posting Permissions

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