Go Back   CodingForums.com > :: Client side development > JavaScript programming

Before you post, read our: Rules & Posting Guidelines

Reply
 
Thread Tools Rate Thread
Enjoy an ad free experience by logging in. Not a member yet? Register.
Old 07-06-2010, 02:24 AM   PM User | #1
johnmerlino
Regular Coder

 
Join Date: Oct 2009
Posts: 189
Thanks: 38
Thanked 3 Times in 3 Posts
johnmerlino is an unknown quantity at this point
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?
johnmerlino is offline   Reply With Quote
Old 07-06-2010, 04:27 AM   PM User | #2
Beagle
Senior Coder

 
Join Date: Jul 2005
Location: New York, NY
Posts: 1,084
Thanks: 4
Thanked 19 Times in 19 Posts
Beagle is an unknown quantity at this point
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".
Beagle is offline   Reply With Quote
Users who have thanked Beagle for this post:
johnmerlino (07-07-2010)
Reply

Bookmarks

Tags
closures, hidden functions, javascript, private methods, return

Jump To Top of Thread


Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 06:12 PM.


Advertisement
Log in to turn off these ads.