Thought I'd pose a question to the list. I haven't actually done much
research into the question myself, so bare with me if I'm being an noob
about it!
I've been using a bit of Backbone and jQuery lately, and a common pattern
might be something like:
[Backbone View]
foo: function()
{
$("li", this.el).each(function() {
.. something ..
});
}
So now, how in the "something" how do I reference the Backbone view, since
"this" is now the element being iterated over?
I have been doing:
foo: function()
{
var context = this;
$("li", this.el).each(function() {
context.model.get("blah");
}
}
While this works, it feels like it might be wrong. At best "context" isn't
really the best name for the var. Is it? Opinions? Arguments?
Thanks! :)
- Marcin
I suggest using `Function::bind`:
*foo: function() {*
* $('li', this.el).each(function() {*
* this.model.get('blah')*
* }.bind(this))*
*}*
This is of course far easier to read when written in CoffeeScript:
*foo: ->*
* $('li', @el).each =>*
* @model.get 'blah'*
You'll need a polyfill to support old browsers (and IE):
-
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#section_5
- https://github.com/kriskowal/es5-shim/blob/c89adef/es5-shim.js#L38-170
Inspiration:
-
http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
David
On 28 October 2011 21:49, Marcin Szczepanski <marcins@gmail.com> wrote:
> Thought I'd pose a question to the list. I haven't actually done much
> research into the question myself, so bare with me if I'm being an noob
> about it!
>
> I've been using a bit of Backbone and jQuery lately, and a common pattern
> might be something like:
>
> [Backbone View]
> foo: function()
> {
> $("li", this.el).each(function() {
> .. something ..
> });
> }
>
> So now, how in the "something" how do I reference the Backbone view, since
> "this" is now the element being iterated over?
>
> I have been doing:
>
> foo: function()
> {
> var context = this;
> $("li", this.el).each(function() {
> context.model.get("blah");
> }
> }
>
> While this works, it feels like it might be wrong. At best "context" isn't
> really the best name for the var. Is it? Opinions? Arguments?
>
> Thanks! :)
>
> - Marcin
>
'context' or 'self' is correct. that is just what you have to do in javascript. On Sat, Oct 29, 2011 at 3:49 PM, Marcin Szczepanski <marcins@gmail.com>wrote: > Thought I'd pose a question to the list. I haven't actually done much > research into the question myself, so bare with me if I'm being an noob > about it! > > I've been using a bit of Backbone and jQuery lately, and a common pattern > might be something like: > > [Backbone View] > foo: function() > { > $("li", this.el).each(function() { > .. something .. > }); > } > > So now, how in the "something" how do I reference the Backbone view, since > "this" is now the element being iterated over? > > I have been doing: > > foo: function() > { > var context = this; > $("li", this.el).each(function() { > context.model.get("blah"); > } > } > > While this works, it feels like it might be wrong. At best "context" isn't > really the best name for the var. Is it? Opinions? Arguments? > > Thanks! :) > > - Marcin >
> > 'context' or 'self' is correct. that is just what you have to do in > javascript. You don't *have to* do this in JavaScript. In fact, function context binding is arguably more idiomatic. David On 28 October 2011 22:00, Dominic Tarr <dominic.tarr@gmail.com> wrote: > 'context' or 'self' is correct. that is just what you have to do in > javascript. > > > On Sat, Oct 29, 2011 at 3:49 PM, Marcin Szczepanski <marcins@gmail.com>wrote: > >> Thought I'd pose a question to the list. I haven't actually done much >> research into the question myself, so bare with me if I'm being an noob >> about it! >> >> I've been using a bit of Backbone and jQuery lately, and a common pattern >> might be something like: >> >> [Backbone View] >> foo: function() >> { >> $("li", this.el).each(function() { >> .. something .. >> }); >> } >> >> So now, how in the "something" how do I reference the Backbone view, since >> "this" is now the element being iterated over? >> >> I have been doing: >> >> foo: function() >> { >> var context = this; >> $("li", this.el).each(function() { >> context.model.get("blah"); >> } >> } >> >> While this works, it feels like it might be wrong. At best "context" isn't >> really the best name for the var. Is it? Opinions? Arguments? >> >> Thanks! :) >> >> - Marcin >> > >
Problem: Local this context is often overridden when using event handlers,
for loops and other callbacks.
A Selection of Solutions:
1. Using the effects of closures to "save" the local this in a different variable:
var self = this;
$("blah").each(function(){
self.doStuff(this);
});
2. Using underscore (http://documentcloud.github.com/underscore/#bind) to
bind the function's this
$("blah").each( _.bind((function(el){
this.doStuff(el);
}), this));
3. Similar approach using underscore but abstracting the anonymous
function to a method
$("blah").each(_.bind(this.doStuff, this));
4. Again but reusable
//constructor
this.boundDoStuff = _.bind(this.doStuff, this);
//elsewhere
$("blah").each(this.boundDoStuff);
5. CoffeeScript with anonymous function
$("blah").each (el) =>
@doStuff el
6. CoffeeScript with method
#method definition
doStuff: (el) =>
#do things with el
#elsewhere
$("blah").each @doStuff
Each of these approaches is mostly acceptable. My favourite is
CoffeeScript with a combination of anonymous functions and methods
(depending on how complex each task is). Though Underscore also works
quite well and is often combined with Backbone.
The first approach is the traditional JQuery way of solving this problem.
- Ben
On Saturday, 29 October 2011 at 4:18 PM, David Chambers wrote:
> > 'context' or 'self' is correct. that is just what you have to do in
javascript.
>
>
> You don't have to do this in JavaScript. In fact, function context
binding is arguably more idiomatic.
>
> David
>
>
> On 28 October 2011 22:00, Dominic Tarr <dominic.tarr@gmail.com
(mailto:dominic.tarr@gmail.com)> wrote:
> > 'context' or 'self' is correct. that is just what you have to do in
javascript.
> >
> >
> > On Sat, Oct 29, 2011 at 3:49 PM, Marcin Szczepanski <marcins@gmail.com
(mailto:marcins@gmail.com)> wrote:
> > > Thought I'd pose a question to the list. I haven't actually done
much research into the question myself, so bare with me if I'm being an
noob about it!
> > >
> > > I've been using a bit of Backbone and jQuery lately, and a common
pattern might be something like:
> > >
> > > [Backbone View]
> > > foo: function()
> > > {
> > > $("li", this.el).each(function() {
> > > .. something ..
> > > });
> > > }
> > >
> > > So now, how in the "something" how do I reference the Backbone view,
since "this" is now the element being iterated over?
> > >
> > > I have been doing:
> > >
> > > foo: function()
> > > {
> > > var context = this;
> > > $("li", this.el).each(function() {
> > > context.model.get("blah");
> > > }
> > > }
> > >
> > > While this works, it feels like it might be wrong. At best "context"
isn't really the best name for the var. Is it? Opinions? Arguments?
> > >
> > > Thanks! :)
> > >
> > > - Marcin
> >
>
A comprehensive list of solutions, you can also use jQuery.proxy to execute a function with a given scope. http://jimmycuadra.com/posts/understanding-jquery-14s-proxy-method http://api.jquery.com/jQuery.proxy/ On Sat, Oct 29, 2011 at 4:34 PM, Ben Taylor <taybenlor@gmail.com> wrote: > Problem: Local this context is often overridden when using event handlers, > for loops and other callbacks. > > A Selection of Solutions: > > 1. Using the effects of closures to "save" the local this in a different > variable: > > var self = this; > $("blah").each(function(){ > self.doStuff(this); > }); > > 2. Using underscore <http://documentcloud.github.com/underscore/#bind> to > bind the function's this > > $("blah").each( _.bind((function(el){ > this.doStuff(el); > }), this)); > > 3. Similar approach using underscore but abstracting the anonymous > function to a method > > $("blah").each(_.bind(this.doStuff, this)); > > 4. Again but reusable > > //constructor > this.boundDoStuff = _.bind(this.doStuff, this); > > //elsewhere > $("blah").each(this.boundDoStuff); > > 5. CoffeeScript with anonymous function > > $("blah").each (el) => > @doStuff el > > 6. CoffeeScript with method > > #method definition > doStuff: (el) => > #do things with el > > #elsewhere > $("blah").each @doStuff > > > Each of these approaches is mostly acceptable. My favourite is > CoffeeScript with a combination of anonymous functions and methods > (depending on how complex each task is). Though Underscore also works quite > well and is often combined with Backbone. > > The first approach is the traditional JQuery way of solving this problem. > > - Ben > > On Saturday, 29 October 2011 at 4:18 PM, David Chambers wrote: > > 'context' or 'self' is correct. that is just what you have to do in > javascript. > > > You don't *have to* do this in JavaScript. In fact, function context > binding is arguably more idiomatic. > > David > > > On 28 October 2011 22:00, Dominic Tarr <dominic.tarr@gmail.com> wrote: > > 'context' or 'self' is correct. that is just what you have to do in > javascript. > > > On Sat, Oct 29, 2011 at 3:49 PM, Marcin Szczepanski <marcins@gmail.com>wrote: > > Thought I'd pose a question to the list. I haven't actually done much > research into the question myself, so bare with me if I'm being an noob > about it! > > I've been using a bit of Backbone and jQuery lately, and a common pattern > might be something like: > > [Backbone View] > foo: function() > { > $("li", this.el).each(function() { > .. something .. > }); > } > > So now, how in the "something" how do I reference the Backbone view, since > "this" is now the element being iterated over? > > I have been doing: > > foo: function() > { > var context = this; > $("li", this.el).each(function() { > context.model.get("blah"); > } > } > > While this works, it feels like it might be wrong. At best "context" isn't > really the best name for the var. Is it? Opinions? Arguments? > > Thanks! :) > > - Marcin > > > > >
If you care about creating idiomatic code, please don't use `_.bind` or
`jQuery.proxy` or any of the other functions that perform this job. Use a
polyfill for `Function::bind` and write code like this:
* this.foo()*
* bar(function (qux) {*
* this.baz()*
* qux(function () {*
* alert(this.quxx)*
* }.bind(this))*
* }.bind(this))
*
It's ugly as fuck, but this is how the language was designed to be used (or
perhaps this aspect of the language was not designed at all). Obviously,
the CoffeeScript equivalent is far more readable:
* @foo()*
* bar (qux) =>*
* @baz()*
* qux =>*
* alert @quxx*
David
On 1 November 2011 16:03, Michael McGlynn <micmcg@gmail.com> wrote:
> A comprehensive list of solutions, you can also use jQuery.proxy to
> execute a function with a given scope.
>
> http://jimmycuadra.com/posts/understanding-jquery-14s-proxy-method
> http://api.jquery.com/jQuery.proxy/
>
>
> On Sat, Oct 29, 2011 at 4:34 PM, Ben Taylor <taybenlor@gmail.com> wrote:
>
>> Problem: Local this context is often overridden when using event
>> handlers, for loops and other callbacks.
>>
>> A Selection of Solutions:
>>
>> 1. Using the effects of closures to "save" the local this in a different
>> variable:
>>
>> var self = this;
>> $("blah").each(function(){
>> self.doStuff(this);
>> });
>>
>> 2. Using underscore
<http://documentcloud.github.com/underscore/#bind>to bind the function's
this
>>
>> $("blah").each( _.bind((function(el){
>> this.doStuff(el);
>> }), this));
>>
>> 3. Similar approach using underscore but abstracting the anonymous
>> function to a method
>>
>> $("blah").each(_.bind(this.doStuff, this));
>>
>> 4. Again but reusable
>>
>> //constructor
>> this.boundDoStuff = _.bind(this.doStuff, this);
>>
>> //elsewhere
>> $("blah").each(this.boundDoStuff);
>>
>> 5. CoffeeScript with anonymous function
>>
>> $("blah").each (el) =>
>> @doStuff el
>>
>> 6. CoffeeScript with method
>>
>> #method definition
>> doStuff: (el) =>
>> #do things with el
>>
>> #elsewhere
>> $("blah").each @doStuff
>>
>>
>> Each of these approaches is mostly acceptable. My favourite is
>> CoffeeScript with a combination of anonymous functions and methods
>> (depending on how complex each task is). Though Underscore also works quite
>> well and is often combined with Backbone.
>>
>> The first approach is the traditional JQuery way of solving this problem.
>>
>> - Ben
>>
>> On Saturday, 29 October 2011 at 4:18 PM, David Chambers wrote:
>>
>> 'context' or 'self' is correct. that is just what you have to do in
>> javascript.
>>
>>
>> You don't *have to* do this in JavaScript. In fact, function context
>> binding is arguably more idiomatic.
>>
>> David
>>
>>
>> On 28 October 2011 22:00, Dominic Tarr <dominic.tarr@gmail.com> wrote:
>>
>> 'context' or 'self' is correct. that is just what you have to do in
>> javascript.
>>
>>
>> On Sat, Oct 29, 2011 at 3:49 PM, Marcin Szczepanski <marcins@gmail.com>wrote:
>>
>> Thought I'd pose a question to the list. I haven't actually done much
>> research into the question myself, so bare with me if I'm being an noob
>> about it!
>>
>> I've been using a bit of Backbone and jQuery lately, and a common pattern
>> might be something like:
>>
>> [Backbone View]
>> foo: function()
>> {
>> $("li", this.el).each(function() {
>> .. something ..
>> });
>> }
>>
>> So now, how in the "something" how do I reference the Backbone view,
>> since "this" is now the element being iterated over?
>>
>> I have been doing:
>>
>> foo: function()
>> {
>> var context = this;
>> $("li", this.el).each(function() {
>> context.model.get("blah");
>> }
>> }
>>
>> While this works, it feels like it might be wrong. At best "context"
>> isn't really the best name for the var. Is it? Opinions? Arguments?
>>
>> Thanks! :)
>>
>> - Marcin
>>
>>
>>
>>
>>
>