3

I have tried to figure this out or search for it on google, i can only find how to create objects, not exactly how functions work. If someone could explain to me how encapsulation works.

function myObject() {

    this.variable1 = "tst";

    this.function1 = function() {
        //Now this function works.  A 'this' function to a private function is ok
        _PrivateFunction1();

        //Here is error one, I cannot seem to call methods within the object
        //from.  
        this.function2();
    }

    this.function2 = function() {
        alert("look! function2!");
    }

    function _PrivateFunction1() {
        //This does work though.  I am confused.
        _PrivateFunction2();
    }

    function _PrivateFunction2() {
        alert("look! PrivateFunction1");

        //this does not work.
        alert(this.variable1);
    }
}
Wayne
  • 59,728
  • 15
  • 131
  • 126
ThePrimeagen
  • 4,462
  • 4
  • 31
  • 44
  • 1
    How do you call the functions? You can call `_PrivateFunction2` from `_PrivateFunction1` because the live in the same scope (both are inside `myObject`). – Felix Kling Feb 24 '11 at 01:54
  • calling this.function2() from inside this.function() likely doesn't work because "this" at that point refers to function2() not to myObject(). – Jeff Feb 24 '11 at 02:00
  • 1
    @Michael yeah you have to save a copy of the actual object like [here](http://jsfiddle.net/DjPw5/1/) note the `var that = this` – qwertymk Feb 24 '11 at 02:04
  • Once again.. My mind is blow. Thanks @qwertymk – ThePrimeagen Feb 24 '11 at 02:05
  • Strange. In Chrome, the call to this.function2() works as desired, but the line alert(this.variable1) does not. This seems inconsistent -- unless scope is preserved in anonymous functions (!?). I tested this by placing alert(this.variable1) at the end of the definition for this.function1, and it worked. Huh. – Seth Feb 24 '11 at 02:08
  • Yeah.. It seems to be very strange. I have grown up in the OO Paradigm, so javascript is... well.. its kind of close, i just do not get it yet. – ThePrimeagen Feb 24 '11 at 02:10
  • What browser are you using? I just tried this in IE8, and got the same behavior as I did in Chrome (i.e., I get an alert that says "look! function2!" when I create an object and call its function1()). Unless I'm misreading your post, you do not get such an alert. – Seth Feb 24 '11 at 02:12
  • 1
    @Seth, @Michael -- It's not strange at all. The call to `this.function2` works because the value of `this` inside `this.function1` is `myObject`. But the value of `this` inside `_PrivateFunction2` is the global object (`window`). So `this.variable1` is looking for a property named `variable1` on the `window` object, which isn't what you intended. How a function is called changes what `this` refers to inside it. Please see my answer below for a much longer explanation. – Wayne Feb 24 '11 at 16:12

3 Answers3

6

I think I can explain this better if we go in reverse order. First, we define some functions:

function _PrivateFunction1() {
    //This does work though.  I am confused.
    _PrivateFunction2();
}

function _PrivateFunction2() {
    alert("look! PrivateFunction1");

    //this does not work.
    alert(this.variable1);
}

This is pretty normal stuff. The only thing that's weird is that they appear inside another function, but that's perfectly fine. JavaScript has function scope, which means that all variables defined inside a function are defined in a new scope. They do not trample on the global namespace. And functions are first-class objects in JavaScript, which means they can be used just like other data types. They can be nested, passed to functions, returned from functions, etc.

Then we run into some trouble:

    function _PrivateFunction2() {
        alert("look! PrivateFunction1");

        //this does not work.
        alert(this.variable1);
    }
}

Functions in JavaScript are always executed in some context which is referred to by the this keyword. When you call a function directly (i.e. like this: functionName()) the context in which that function executes is the global window object. So, inside _PrivateFunction2, this.variable1 is equivalent to window.variable1 which is probably not what you meant.

You probably wanted to refer to the current instance of myobject which is what this refers to outside of _PrivateFunction2. You can preserve access to this in an inner scope by storing a reference to it in another variable:

var _this = this;

function _PrivateFunction2() {
    alert("look! PrivateFunction1");

    //this does not work.
    alert(_this.variable1);
}

There's something subtle here you should notice. _PrivateFunction2 has access to the variables defined in its lexical scope, which is why it can access _this. This will be important later.

Next up:

    function _PrivateFunction1() {
        //This does work though.  I am confused.
        _PrivateFunction2();
    }

This should be the most normal-looking section to you, I would think. There's nothing strange going on here. Just one regular function calling another one. Don't be confused by the fact that these are nested inside myObject. That changes the scope they're in, but not much else.

Next we define some instance variables and methods:

this.variable1 = "tst";

this.function1 = function() {
    //Now this function works.  A 'this' function to a private function is ok
    _PrivateFunction1();

    //Here is error one, I cannot seem to call methods within the object
    //from.  
    this.function2();
}

this.function2 = function() {
    alert("look! function2!");
}

Here this really does refer to myObject, assuming -- and it's an important assumption -- that myObject was called with the new operator, like this:

var obj = new myObject();

If it had been called like this:

var obj = myObject();

Then this would refer to the window object, just like it did for the functions we saw earlier. The key takeaway is that the value of this is not fixed. It's determined by the way in which the function is called. There are even ways to set it to an arbitrary object explicitly.

The value of this inside this.function1 will also be the current instance of myObject, because it will most likely be used like this:

var obj = new myObject();
obj.function1();

Writing object.method() sets this to object inside method.

So how is this.function1 able to call _PrivateFunction1()? Just as we saw earlier when saving the value of this for use inside a nested function, _PrivateFunction1() is just another object defined in this.function1's lexical scope, so it is available for its use, just as _this was earlier.

And it's because of closure that these private variables are still alive long after myObject has returned.

Footnote: Because failing to use new when instantiating objects breaks things so spectacularly without warning, it's considered good practice to capitalize the names of functions you intend to be used as a constructor. So myObject should really be MyObject.

Community
  • 1
  • 1
Wayne
  • 59,728
  • 15
  • 131
  • 126
  • 2
    Thank you for the more verbose answer. I have a degree in CS so it helps. Since i always studied Java/C#, 'this' keyword, in the light of using inside of an object, really confused me with javascript. With this i should be better at javascript! thanks buddy – ThePrimeagen Feb 24 '11 at 18:40
0

You have to save a copy of the actual object like here note the var that = this

Tested in chrome and FF

qwertymk
  • 34,200
  • 28
  • 121
  • 184
0

for encapsulation I would prefer module pattern like

var someMethod = function(){



     var i, 
         length,

     // public method
     public = function(num1, num2){
            return num1+num2;
     },

    //private method
     _private = function(){};

    //exposing the public method

     return{
       public:public
     }

};

var callPublic = someMethod();
callPublic.public(20, 30);// call the public method and return 50

now , if you try to call that private method like

callPublic._private();//it will return not a function since its not been exposed

There are lot of other pattern to encapsulate your methods but module pattern is most common. Hope ot will help you how to encapsulate data in javascript.

paul
  • 1,124
  • 9
  • 27
  • 45