Created
May 19, 2011 01:58
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
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
Another pattern you could include, even though it's douchey and needlessly verbose
http://jsfiddle.net/rwaldron/X5CYF/