Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a 'this' reference to a 2nd level prototype function

I'm fairly certain this isn't possible, but wanted to see if anyone had some ingenious ideas as to how to make it possible.

I want the following code to work:

var x = new foo();
x.a.getThis() === x; // true

In other words, I want x.a.getThis to have a reference to this being x in this case. Make sense?

In order to get this to work one level deep is simple:

function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true

One thing, I want this to work as a prototype, no "cheating" by manually binding to this:

function foo(){
    this.a = {
        getThis : (function(){ return this; }).bind(this)
    };
}

Although the above is a perfect functional example of what I'm trying to achieve, I just don't want all the extra functions for each instance :)

FYI, the actual use case here is that I'm creating classes to represent Cassandra objects in node and I want to be able to reference a super-column --> column-family --> column via foo.a.b and keep a reference to foo in the deep function.


1 Answers

You can't do this without a forced bind of some kind. You say you don't want to "cheat" but this breaks the standard rules about what this is, so you have to cheat. But JS lets you cheat, so it's all good.

BTW, for what it's worth coffee script makes this so trivial.

foo = ->
  @a = getThis: => this

The fat arrow => preserves the context of this for from the scope it was called in. This allows you to easily forward the context to another level.

That code gets compiled to this JS:

var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
  return this.a = {
    getThis: __bind(function() {
      return this;
    }, this)
  };
};

Which basically just does what you say you do not want to do.


Or if the value doesn't have to this specifically, you can set the "owner" in the child object.

var A = function(owner) {
  this.owner = owner;
};
A.prototype.getThis = function() {
  return this.owner;
};
var Foo = function() {
  this.a = new A(this);
};

var foo = new Foo();

if (foo.a.getThis() === foo) {
    alert('Happy dance');
} else {
    window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}

http://jsfiddle.net/4GQPa/

And the coffee script version of that because I am a passionate and unreasonable zealot for it:

class A
  constructor: (@owner) ->
  getThis: -> @owner

class Foo
  constructor: -> @a = new A(this)

foo = new Foo()
if foo.a.getThis() is foo
  alert 'Happy Dance'
else
  window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
like image 177
Alex Wayne Avatar answered Mar 03 '26 08:03

Alex Wayne



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!