Deiwin
Deiwin

Reputation: 447

How to get the outer "this" reference in JavaScript

So I have a class lets call it A. For this class I have written a few functions which I can call like this:

var a = new A();
a.getSomething();
a.putSomething();
a.delSomething();

And so on. Now I thought I'd organize it a bit So it wouldn't get too cluttered and would look like a bit more like this:

a.something.get();
a.something.put();
a.something.del();

And this is how I tried to achieve this:

A.prototype.something = {
  get: function(){...},
  put: function(){...},
  del: function(){...}
};

But these functions (get, put and del) still need to access the common objects/functions found in A, so I need a reference to A, but I don't know how this can be achieved.

One option I found goes like that:

A.prototype.something = function(){
  var that = this;
  return {
    get: function(){...},
    ...
  };
}; 

And 'that' would be used in those (get, put and del) functions instead of 'this'. But this would mean I would have to call these functions in such way:

a.something().get();
...

Which doesn't seem very nice to me. So is there a way I could organize these things the way I originally planned?

Upvotes: 13

Views: 3318

Answers (3)

Kernel James
Kernel James

Reputation: 4064

function A() {
  this.something = this;
}
A.prototype = {
  get: function(){...},
  put: function(){...},
  del: function(){...}
};

therefore:

a.something.get();
a.something.put();
a.something.del();

Upvotes: 0

RobG
RobG

Reputation: 147403

So I have a class

Javascript doesn't have classes. It has prototype inheritance that can emulate classes to a limited extent, but that isn't worthwhile purely for the sake of emulating classes. Much better to make optimal use of built–in language features rather than trying to make javascript emulate some other language.

So you have a constructor...

I have written a few functions which I can call like this:

var a = new A();
a.getSomething();
a.putSomething();
a.delSomething();

Presumably those methods are all on A.prototype.

And so on. Now I thought I'd organize it a bit So it wouldn't get too cluttered and would look like a bit more like this:

a.something.get();
a.something.put();
a.something.del();

That isn't less cluttered (to me). I guess there is some common thing that is done by something, and that its get, put, etc. methods want to operate on a not on something.

The value of this is set by the call, there is no other way to set its value other than with ES5 bind. So the method being called must have access to a somehow. Other answers show how to do that with a closure, but the consequence is that each instance must have its own something object and attached methods.

The following is similar, but gets rid of the closure and puts the methods on Something.prototype for a bit of efficiency:

function A(name) {
    this.name = name;
    this.something = new Something(this);
}


function Something(that){
    this.that = that;
}

Something.prototype.get = function() {
    return this.that.name;
}
Something.prototype.put = function(prop, value) {
    this.that[prop] = value;
}

var a = new A('a');

alert(a.something.get());     // a
a.something.put('name', 'z');
alert(a.something.get());     // z

So you can have multiple somethings, each with different put, get, etc. methods. But the intervening something object is really just a device that uses more memory (probably a tiny amount) and requires an extra character. Simpler to keep the something methods on A.prototype and not have to type the extra dot (.).

Upvotes: 5

Eric
Eric

Reputation: 97591

You can't add this to the prototype, because the something member is not the same on all objects - internally, its methods must obtain a closure to the outer object, which is not possible to obtain at the time of execution.

You need to do it in the constructor:

function A() {
    var that = this;
    this.something = { 
       get: function(){...}, 
       ... 
    };
}

Upvotes: 7

Related Questions