Scope in JavaScript is just from which door you entered

Put simply, we entered BigComputer via new, so this meant “the new object.” On the other hand, we entered the_question via deep_thought, so while we’re executing that method, this means “whatever deep_thought refers to”. this is not read from the scope chain as other variables are, but instead is reset on a context by context basis.

Javascript’s scoping has been one of most confusing things about it, just as Ruby’s metaclass and object model is the most confusing things about it. If you’re looking to expand the horizon of what you understand about programming languages, it’s worth it to figure out javascript scoping.

The paragraph gave a good way to think about it:  this changes based on the object that calls the method.  It only gets confusing when you start passing around functions and using callbacks, which is most of the power of functional programming.

As an example, here, I was using an anonymous function as a callback in the request() method.  But it doesn’t work!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* This sample uses jQuery */

/* This doesn't work.
*
* Here, notice the success callback uses the data variable, except when called,
* the anonymous function can't access the data variable, since it's defined within
* the scope of the anonymous object that's sent to the request() method.
*/
function someEvent(event) {
    var data = { 'update-success' : "result_list", 'update-failure' : "error_list" };

    return request({ url : this.href,
                     success : function(response_html) {
                         $("#" + data['update-success']).html(response_html);
                     }
                   });
};

/* This works.
*
* Here, we've moved the success callback out of the context of the anonymous object
* and set it as the context of the someEvent() function. Thus, it will be able
* to access the data variable.
*/
function someEvent(event) {
    var data = { 'update-success' : "result_list", 'update-failure' : "error_list" };

    var success_callback = function(response_html) {
        $("#" + data['update-success']).html(response_html);
    };
    
    return request({ url : this.href,
                     success : success_callback
                   });
};

So that’s just one way to solve it.  If you’re using Prototype, you can also try using the bind() method.  jQuery doesn’t have an equivalent bind method, as hard as I looked for it at one time.  I was just about to write it myself (as it’s not too hard), but according to the a list apart article on Getting out of binding situations in javascript:

jQuery does not provide such a binding facility. The library’s philosophy favors closures over binding and forces users to jump through hoops (that is, manually combine lexical closures and apply or call, much as other libraries do internally) when they actually need to pass along a piece of code referring to “instance members.”

So while I use closures extensively in Ruby, I haven’t had to explicitly think about the scope until I was using closures in Javascript.  Huzzah.  Hopefully, it’ll prompt you to take a deeper look at Javascript.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s