Fabulous Adventures In Coding

Eric Lippert's Blog

Guru meditations on scope chains of closures

I just had a really interesting meeting with some of the scripting community MVPs.  I may write up some notes on that meeting here next week, so watch this space.

In other news, someone asked me last night (and I quote)

Oh ECMA guru, can you provide a succinct explanation of why the following code works, but if I replace x with this it fails?

Number.prototype.times = function(f) {
  for(var i = 0; i < this; i++)
    f();
}
Number.prototype.raiseTo = function(n) {
  var answer = 1;
  var x = this;
  n.times(function(){ answer = x * answer;}); // succeeds
//n.times(function(){ answer = this * answer;}); // fails!
  return answer;
}
(3).raiseTo(2).raiseTo(5);

Well I'd hardly describe myself as a guru, but I take the questioner's point -- surely if you set x to this then x and this should be aliases for each other, right?

Often. But not in this case.

The inner function's execution context contains a scope chain that includes the variable object of the outer function, so the inner function can see x by looking up the scope chain. But this is not a variable, so it is not member of the outer function's variable object. Rather, it is a member of the outer function's execution context.

Therefore the inner function's execution context gets the global this, in accordance with the ECMAScript specification, revision 3, section 10.2.3:

The caller provides the this value. If the this value provided by the caller is not an object (including the case where it is null), then the this value is the global object.

The global object is not something that can be multiplied, so the alternate version of the program fails.

The code above was of course not real production code, it was just code that came up while testing an engine implementation. Obviously JScript already has a built-in power function that works much better than this crazy thing. But I'm in an expansive mood, so next time I'll talk a bit about some of the shortcomings of this programming style, and some ideas for improving it.

Published Friday, September 30, 2005 12:41 PM by Eric Lippert
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Lance Fisher said:

Speaking about this kind of thing. I'd love to hear what you think about Atlas, if you want to write up a post on it.
September 30, 2005 7:00 PM
 

Slava said:

Interesting, even if nothing new. I can hardly wait for the next post, however.
October 1, 2005 9:13 AM
 

Eric Lippert said:

Re: nothing new: The JScript and VBScript portions of my blog are about languages that we started developing ten years ago and stopped developing five years ago. There shouldn't be anything new in those posts! The new stuff is in my VSTO and C# posts.

Re: atlas: I talk occasionally with the Atlas team management to keep up-to-date on what they're doing at a broad level, but I am no expert on the deep technical side. What do YOU think of Atlas? What more would you like to see?
October 1, 2005 11:34 AM
 

Slava said:

Heh, well, maybe there shouldn't be anything new, but from time to time I do find new and interesting thing, perhaps something old from a new perspective. And even when it's not something new, I still enjoy reading about it, I often find something "new" (or forgotten) in the "old" stuff.

I'm fresh out of college so I didn't have a chance to follow JScript and VBScript when it just came out, but I found that script related juicy articles are scattered around the web, and your blog is one of the greatest sources:)
October 1, 2005 2:54 PM
 

Eric Lippert said:

Thanks! I'm glad you enjoy it. If you have suggestions for future subjects -- new or old -- let me know. I'm always looking for more ideas.
October 2, 2005 2:55 AM
 

Lance Fisher said:

I haven't really got to play with Atlas much so I can't say a whole lot, but what I saw at the PDC was very impressive. I didn't expect it be as extensive at it seems, essentially turning JScript into an object-oriented language. It looks like it is designed very well. However, it looks like it still takes quite a bit of work to make AJAX-like websites, and the more I get into it the more complex it gets. I'm looking forward to checking it out more in depth - I just need to find the time.
October 3, 2005 12:08 PM
 

kbiel said:

Funny, I would said that it failed because 'this' inside the annonymous function referred the function object for the annonymous function rather than it being scoped out to the global object.
October 3, 2005 3:10 PM
 

Eric Lippert said:

Why would "this" ever refer to the function? If you had

function foo() { print(this==foo); }

you'd expect that to be false, right? It's no different for anonymous functions.

(Of course, that might be true in some really bizarre case, like "foo.foo=foo; foo.foo();" -- but normally the "this" reference should never be the function.)


October 3, 2005 4:15 PM
 

kbiel said:

My confusion came from me being an old hack at javascript from the early days, but my statement was wrong even in that context. There is one case where "this" refers to the function object itself that is in the "new" context. Such as:

function foo (bar) { this.bar = bar; }
var baz = new foo(42);

But that case obviously does not apply to anonymous functions invoked as methods to another object.
October 4, 2005 2:09 AM
 

Eric Lippert said:

No, "this" doesn't refer to the function object in that case either. It refers to the value that is about to be assigned to baz. Try it!

function foo(bar){ print(this==foo); }
var baz = new foo(42);

That will be false for sure.
October 4, 2005 9:35 AM
 

kurtiss said:

If you'd really like to use the 'this' keyword in an anonymous function, you could do so like this:

Number.prototype.instanceFn = function(f)
{
var oThis = this;
return function() { f.apply(oThis, arguments); }
}

...

Number.prototype.raiseTo = function(n) {
var answer = 1;
n.times(this.instanceFn(function(){ answer = this * answer;})); // succeeds!
return answer;
}

Of course, the resulting call stack can get pretty messy at this point.
October 4, 2005 10:53 AM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker