Skip to content

Instantly share code, notes, and snippets.

@cowboy
Created May 19, 2011 01:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cowboy/980016 to your computer and use it in GitHub Desktop.
Save cowboy/980016 to your computer and use it in GitHub Desktop.
JavaScript: A few ways to work around the lack of `this` propagation in inner functions
var value = 'FAIL!!';
var obj = { value: 9000 };
// This is totally broken, because inner functions don't "inherit" the outer
// function's `this` value. Instead, their `this` value is the global object.
obj.broken = function() {
function addToValue(n) {
return this.value + n;
}
return addToValue(1);
};
obj.broken() // 'FAIL!!1'
// You can store a reference to the outer function's `this` value and
// reference that variable in the inner function. Super-easy, but it might
// feel a little gross.
obj.byreference = function() {
var that = this;
function addToValue(n) {
return that.value + n;
}
return addToValue(1);
};
obj.byreference() // 9001
// You can, of course, also use call invocation to obviate the need for
// that extra variable, but if you're going to be doing it a lot, it's going
// to get awfully verbose real fast.
obj.callinvocation = function() {
function addToValue(n) {
return this.value + n;
}
return addToValue.call(this, 1);
};
obj.callinvocation() // 9001
// You can also proxy the inner function such that the returned function
// is always called with the "correct" `this` value. Of course, if you want
// to get `this` dynamically, you're going to either need to store a reference
// to the outer function's `this` value in proxy or specify `obj` explicitly.
obj.proxy = function(fn) {
var context = this;
return function() {
return fn.apply(context, arguments);
};
};
obj.proxying = function() {
var addToValue = this.proxy(function(n) {
return this.value + n;
});
return addToValue(1);
};
obj.proxying() // 9001
// Of course, if you only care about supporting the latest browsers, you can
// use Function#bind to do the aforementioned "proxying" stuff natively.
obj.bound = function() {
var addToValue = function(n) {
return this.value + n;
}.bind(this);
return addToValue(1);
};
obj.bound() // 9001
@rwaldron
Copy link

Another pattern you could include, even though it's douchey and needlessly verbose

var // 
name = 'window baby', 
obj = {
  name: 'object baby',
  broken: function() {
    return (function () {
      return this.name;
    }.bind(this))();
  }
};

console.log(
  obj.broken()
);

http://jsfiddle.net/rwaldron/X5CYF/

@cowboy
Copy link
Author

cowboy commented May 19, 2011

Thanks, Rick - I actually simplified your code a bit, take a look!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment