Rate it!
[Edit Description]
I have recently stumbled upon a blog post by Remy Sharp on detecting global variable leaks. As you probably know, Javascript is notorious at making such leaks way too easy. The problem is mainly with undeclared assignments which result in global variable declarations when variables are not found in the scope chain.
(function(){ var x = 1; // <== accidentally changed "," to ";" y = 2; // <== `y` is now a global variable })();
Remy solves the problem with a bookmarklet that creates a blank context (essentially a window in an empty iframe), then uses that clean context to get the difference with the main one. The list of found variables is dumped into a console.
It's worth mentioning that JSLint already allows detecting undeclared assignments, but JSLint can hurt feelings so we won't use it. Well, actually JSLint performs so many validations, that it's not always possible to detect undeclared assignments in huge scripts of legacy applications (like the one I wanted to examine). Running a test such as in this bookmarklet can be "applied on" any script.
The bookmarklet worked like a charm, but as soon as I plugged it into one of our applications, I was greeted with dozens of Prototype and Scriptaculous -related methods. On top of those, there were few google analytics and Mozilla -specific ones. Unfortunately, the original code was obfuscated and almost unreadable so I reproduced it from the scratch, this time making it possible to toggle certain property sets on and off. These property sets are - Prototype, Scriptaculous, Mozilla, Google Analytics and Firebug ones. The code is structured in such way that it should be easy to augment it with additional sets.
Source (thinkweb2.com)
[Edit Javascript]
Show Source Code
javascript%3A%2520%28function%28%29%7Bfunction%2520getPropertyDescriptors%28object%29%7Bvar%2520props%3D%7B%7D%3Bfor%28var%2520prop%2520in%2520object%29%7Bprops%5Bprop%5D%3D%7Btype%3Atypeof%2520object%5Bprop%5D%2Cvalue%3Aobject%5Bprop%5D%7D%7D%2520return%2520props%3B%7D%2520function%2520getCleanWindow%28%29%7Bvar%2520elIframe%3Ddocument.createElement%28%27iframe%27%29%3BelIframe.style.display%3D%27none%27%3Bdocument.body.appendChild%28elIframe%29%3BelIframe.src%3D%27about%3Ablank%27%3Breturn%2520elIframe.contentWindow%3B%7D%2520function%2520appendControl%28el%2Cname%29%7Bvar%2520elCheckbox%3Ddocument.createElement%28%27input%27%29%3BelCheckbox.type%3D%27checkbox%27%3BelCheckbox.checked%3Dtrue%3BelCheckbox.id%3D%27__%27+name%3Bvar%2520elLabel%3Ddocument.createElement%28%27label%27%29%3BelLabel.htmlFor%3D%27__%27+name%3BelLabel.innerHTML%3D%27Exclude%2520%27+name+%27%2520properties%3F%27%3BelLabel.style.marginLeft%3D%270.5em%27%3Bvar%2520elWrapper%3Ddocument.createElement%28%27p%27%29%3BelWrapper.style.marginBottom%3D%270.5em%27%3BelWrapper.appendChild%28elCheckbox%29%3BelWrapper.appendChild%28elLabel%29%3Bel.appendChild%28elWrapper%29%3B%7D%2520function%2520appendAnalyze%28el%29%7Bvar%2520elAnalyze%3Ddocument.createElement%28%27button%27%29%3BelAnalyze.id%3D%27__analyze%27%3BelAnalyze.innerHTML%3D%27Analyze%27%3BelAnalyze.style.marginTop%3D%271em%27%3Bel.appendChild%28elAnalyze%29%3B%7D%2520function%2520appendCancel%28el%29%7Bvar%2520elCancel%3Ddocument.createElement%28%27a%27%29%3BelCancel.href%3D%27%23%27%3BelCancel.innerHTML%3D%27Cancel%27%3BelCancel.style.cssText%3D%27color%3A%23eee%3Bmargin-left%3A0.5em%3B%27%3BelCancel.onclick%3Dfunction%28%29%7Bel.parentNode.removeChild%28el%29%3Breturn%2520false%3B%7D%3Bel.appendChild%28elCancel%29%3B%7D%2520function%2520initConfigPopup%28%29%7Bvar%2520el%3Ddocument.createElement%28%27div%27%29%3Bel.style.cssText%3D%27position%3Afixed%3B%2520left%3A10px%3B%2520top%3A10px%3B%2520width%3A300px%3B%2520background%3Argba%2850%2C50%2C50%2C0.9%29%3B%27+%27-moz-border-radius%3A10px%3B%2520padding%3A1em%3B%2520color%3A%2520%23eee%3B%2520text-align%3A%2520left%3B%27+%27font-family%3A%2520%22Helvetica%2520Neue%22%2C%2520Verdana%2C%2520Arial%2C%2520sans%2520serif%3B%2520z-index%3A%252099999%3B%27%3Bfor%28var%2520prop%2520in%2520propSets%29%7BappendControl%28el%2Cprop%29%3B%7D%2520appendAnalyze%28el%29%3BappendCancel%28el%29%3Bdocument.body.appendChild%28el%29%3B%7D%2520function%2520getPropsCount%28object%29%7Bvar%2520count%3D0%3Bfor%28var%2520prop%2520in%2520object%29%7Bcount++%3B%7D%2520return%2520count%3B%7D%2520function%2520shouldDeleteProperty%28propToCheck%29%7Bfor%28var%2520prop%2520in%2520propSets%29%7Bvar%2520elCheckbox%3Ddocument.getElementById%28%27__%27+prop%29%3Bvar%2520isPropInSet%3DpropSets%5Bprop%5D.indexOf%28propToCheck%29%3E-1%3Bif%28elCheckbox.checked%26%26isPropInSet%29%7Breturn%2520true%3B%7D%7D%7D%2520function%2520analyze%28%29%7Bvar%2520global%3D%28function%28%29%7Breturn%2520this%3B%7D%29%28%29%2CglobalProps%3DgetPropertyDescriptors%28global%29%2CcleanWindow%3DgetCleanWindow%28%29%3Bfor%28var%2520prop%2520in%2520cleanWindow%29%7Bif%28globalProps%5Bprop%5D%29%7Bdelete%2520globalProps%5Bprop%5D%3B%7D%7D%2520for%28var%2520prop%2520in%2520globalProps%29%7Bif%28shouldDeleteProperty%28prop%29%29%7Bdelete%2520globalProps%5Bprop%5D%3B%7D%7D%2520console.dir%28globalProps%29%3Bconsole.log%28%27Total%2520amount%2520of%2520properties%3A%2520%27+getPropsCount%28globalProps%29%29%3B%7D%2520var%2520propSets%3D%7B%27Prototype%27%3A%27%24%24%2520%24A%2520%24F%2520%24H%2520%24R%2520%24break%2520%24continue%2520%24w%2520Abstract%2520Ajax%2520Class%2520Enumerable%2520Element%2520Field%2520Form%2520%27+%27Hash%2520Insertion%2520ObjectRange%2520PeriodicalExecuter%2520Position%2520Prototype%2520Selector%2520Template%2520Toggle%2520Try%27.split%28%27%2520%27%29%2C%27Scriptaculous%27%3A%27Autocompleter%2520Builder%2520Control%2520Draggable%2520Draggables%2520Droppables%2520Effect%2520Sortable%2520SortableObserver%2520Sound%2520Scriptaculous%27.split%28%27%2520%27%29%2C%27Firebug%27%3A%27loadFirebugConsole%2520console%2520_getFirebugConsoleElement%2520_FirebugConsole%2520_FirebugCommandLine%2520_firebug%27.split%28%27%2520%27%29%2C%27Mozilla%27%3A%27Components%2520XPCNativeWrapper%2520XPCSafeJSObjectWrapper%2520getInterface%2520netscape%2520GetWeakReference%27.split%28%27%2520%27%29%2C%27GoogleAnalytics%27%3A%27gaJsHost%2520gaGlobal%2520_gat%2520pageTracker%27.split%28%27%2520%27%29%7D%3BinitConfigPopup%28%29%3Bdocument.getElementById%28%27__analyze%27%29.onclick%3Danalyze%3B%7D%29%28%29%3B
javascript variable global debug web development