0

I am kind of new to OOP in JS. I would like to know why when creating sub-objects, this stops referring to the main object AFTER the second level of subobjects.

function Clase()
{
    this.__construct = function()
    {
    this.paginator();            
    alert('__construct finished');
    };                

    this.paginator = function()
    {

        this.paginator.title = function()
        {
            this.paginator.title.set_offsets  = function()
            {
                alert('paginator.title.set_offsets executed!');

            };
        };

        this.paginator.title(); //instantiating

        alert('subobject paginator created');            
     };

    this.__construct();
}

var instancia = new Clase();

instancia.paginator.title.set_offsets();

http://jsfiddle.net/WYWwE/

The error is: this.paginator is undefined.

And now, if I use closures, it works perfectly:

function Clase()
{
    self = this;

    this.__construct = function()
    {
        this.paginator();            
        alert('__construct finished');
    };                

    this.paginator = function()
    {

        self.paginator.title = function()
        {
            self.paginator.title.set_offsets  = function()
            {
                alert('instancia.paginator.title.set_offsets() executed');

            };
     };
     self.paginator.title();

     alert('this.paginator created');
};

this.__construct();
}

var instancia = new Clase();

instancia.paginator.title.set_offsets();

http://jsfiddle.net/esjHu/

So, AFAIK after some point, "this" stops refering to the class "Clase" and refers to something else. If so, is it a good practice to use closures this way?

Is it also correct to start the class with self = this; and from then on use ONLY "self"? for instance: http://jsfiddle.net/byGRX/

Cœur
  • 37,241
  • 25
  • 195
  • 267
bgusach
  • 14,527
  • 14
  • 51
  • 68
  • 'This' can change based on the context you're in. A similar question was asked [here](http://stackoverflow.com/questions/3127429/javascript-this-keyword), and the first response links to a good article on the subject. – Bubbles Sep 10 '12 at 17:34
  • Thanks, the link was interesting, but it does not answer my question. I still don't know why 'this' is lost when I go down in the object layers. – bgusach Sep 11 '12 at 07:17

2 Answers2

3

You lose the reference to the "original" this when you nest functions. To remedy do the following:

function Clase() {
    var that = this;


    this.paginator = {

        title: {

            set_offsets: function() {
                alert('paginator.title.set_offsets executed!');

            }
        }
    };
};

var foo = new Clase();

foo.paginator.title.set_offsets();​

http://jsfiddle.net/vd5YK/

Alex
  • 34,899
  • 5
  • 77
  • 90
0

You don't lose reference to the this object, here's what happens:

For example:

function Class() {

  this.func1 = function () {

    this.func1.func2 = function () {
      alert('Works!');
    };

  };

  this.func1.func2();
}

x = new Class();

Now, the reason you get an error saying that func2 doesn't exist is because the function object for func2 isn't constructed until you call func1:

function Class() {

  this.func1 = function () {

    this.func1.func2 = function () {
      alert('Works!');
    };

  };

  this.func1();
  this.func1.func2();
}

x = new Class();

And now it works.

EDIT:

So, why doesn't this work:

function Class() {

    this.func1 = function() {

        this.func1.func2 = function() {

            this.func1.func2.func3 = function() {
                alert('works!');
            };

            this.func1.func2.property = 5;
        };

    };

    this.func1();
    this.func1.func2();
}

x = new Class();

x.func1.func2.func3();

Basically, what your trying to do is add a property named property and a method named func3 to the function object of func2, but the problem is that func2 isn't constructed before calling func1. It's the same as doing:

function Class() {

    this.func1 = function() {

        this.func1.func2 = function() {};

    };

    this.func1.func2.func3 = function() {
        alert('works!');
    };
    this.func1.func2.property = 5;

    this.func1();
    this.func1.func2();
}

x = new Class();

x.func1.func2.func3();

If you want it to work you need first construct the function object for func2 by calling func1:

function Class() {

    this.func1 = function() {

        this.func1.func2 = function() {};

    };

    this.func1();

    this.func1.func2.func3 = function() {
        alert('works!');
    };
    this.func1.func2.property = 5;

    // this.func1.func2();

}

x = new Class();

x.func1.func2.func3();
alert(x.func1.func2.property);
Korikulum
  • 2,529
  • 21
  • 25
  • Hi, That also works for me. The problem comes when I want to create another sublevel of objects. Like this: http://jsfiddle.net/SwNPs/ As long as I use this. I lose the reference to the object from the 2nd level on. Thanks anyway!! – bgusach Sep 11 '12 at 06:03
  • @ikaros45 I've extended my answer. – Korikulum Sep 11 '12 at 14:01
  • Good explanation Korikulum, but the code turns out to be too messy. I'm going for Xander's solution. I really don't love literal notation but code is much cleaner and simple. Thank you! – bgusach Sep 11 '12 at 15:29