Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
JScript, as I noted yesterday, is a functional language. That doesn't mean that it works particularly well (though I hope it does) but rather that it treats functions as first-class objects. Functions can be passed around and assigned to variables just as strings or integers can be.
A reader commented yesterday that "closures are your friends". Well, actually there are important situations where closures are NOT your friends! Let's talk a bit about those. First off, what's a closure?
Consider the following (contrived and silly, but pedagocially clear) code:
function AddFive(x) { return x + 5;}
function AddTen(x) { return x + 10;}
var MyFunc;if (whatever) MyFunc = AddFive;else MyFunc = AddTen;print(MyFunc(123)); // Either 133 or 128.
Here we have a typical functional scenario. We're deciding which function to call based on some runtime test. Now, one could imagine that you'd want to generalize this notion of an "adder function", and you would not want to have to write dozens and dozens of adders. What we can do is create an adder factory:
function AdderFactory(y) { return function(x){return x + y;}}
var MyFunc;if (whatever) MyFunc = AdderFactory(5);else MyFunc = AdderFactory(10);print(MyFunc(123)); // Either 133 or 128.
The anonymous inner function remembers what the value of y was when it was returned, even though y has gone away by the time the inner function is called! We say that the inner function is closed over the containing scope, or for short, that the inner function is a closure.
This is an extremely powerful functional language feature, but it is important to not misuse it. There are ways to cause memory-leak-like situations using closures. Here's an example:
<body><div class='menu-bar' id='myMenu'></div><script language='javascript'>var menu = document.getElementById('myMenu');AttachEvent(menu);function AttachEvent(element) { element.attachEvent( "onmouseover", mouseHandler); function mouseHandler(){ /* whatever */ }}</script></body>
Someone has, for whatever reason, nested the handler inside the attacher. This means that the handler is closed over the scope of the caller; the handler keeps around a reference to element which is equal to menu, which is that div. But the div has a reference to the handler.
That's a circular reference.
Now, the JScript garbage collector is a mark-and-sweep GC so you'd think that it would be immune to circular references. But the IE div isn't a JScript object; it is not in the JScript GC, so the circular reference between the div and the handler will not be broken until the browser completely tears down the div.
Which never happens.
This page used to say that IE tears down the div when the page is navigated away, but it turns out that that's not right. Though IE did briefly do that, the application compatibility lab discovered that there were actually web pages that broke when those semantics were implemented. (No, I don't know the details.) The IE team considers breaking existing web pages that used to work to be way, way worse than leaking a little memory here and there, so they've decided to take the hit and leak the memory in this case.
Don't use closures unless you really need closure semantics. In most cases, non-nested functions are the right way to go.
The Evolution of the Web Developer In the past, memory leaks haven't posed huge problems for Web developers. Pages were kept relatively simple and navigation between different locations within a site was a great way to clean up any loose memory. If there..
PingBack from http://amref.wordpress.com/2007/06/01/fabulous-adventures-in-coding/
PingBack from http://sudarmuthu.com/blog/2005/06/23/is-firefox-104-unstable.html
We're getting hung up on the stack management aspects of recursive programming. Why do we need a stack
在接下来的内容中,我们会讨论内存泄露方式,并为每种方式给出示例。其中一个重要的示例是JScript中的Closure技术,另一个示例是在事件执行中使用Closures。当你熟悉本示例后,你就能找出并修改你已有的大多数内存泄漏问题,但是其它Closure相关的问题可能又会被忽视。
Closers are a wonderful concept that works very well on all other languages that have it, even server side JavaScript. Too bad the implementers of JavaScript from browser makers have decided that garbage collection is done on two layers, one from page DOM and one from the JavaScript engine, so from what could be a great tool in making better code in a real functional way, we have to write procedural code because the language implementers messed up.
PingBack from http://journal.suteki.nu/2008/02/26/scheme-programming-guides/