Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the outer "this" reference in JavaScript

Tags:

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?

like image 851
Deiwin Avatar asked Aug 30 '12 00:08

Deiwin


People also ask

How do you access outer this in JavaScript?

var comparatorFactory = function(data) { return function(a,b) { return data[a] - data[b]; } }; function some_object(...) { var so = this; so. data = {...}; var comparator = comparatorFactory(so. data); ...

What does this => mean in JavaScript?

It's a new feature that introduced in ES6 and is called arrow function. The left part denotes the input of a function and the right part the output of that function.

Is there a this in JavaScript?

In JavaScript, the this keyword refers to an object. Which object depends on how this is being invoked (used or called). The this keyword refers to different objects depending on how it is used: In an object method, this refers to the object.

What is $$ in JavaScript?

$ and $$ are valid variable names in JavaScript, they have no special meaning. Usually they set their value to library instances, in your example if you check the closure call, at the end of the file you'll see that $ is jQuery in this case if it is defined and $$ is cytoscape.


2 Answers

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(){...}, 
       ... 
    };
}
like image 196
Eric Avatar answered Nov 15 '22 14:11

Eric


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 (.).

like image 26
RobG Avatar answered Nov 15 '22 14:11

RobG