Closure Inspector

From FirebugWiki

Jump to: navigation, search

Closure inspector is a feature available from Firebug 1.11.2 that makes it possible to access JavaScript closure variables.

Contents

[edit] Closures

If you already know what closures are, skip to Closure Inspector.

[edit] Definition

You might have seen or even used closures without knowing the formal definition.

Wikipedia says:

In computer science, a closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables) of that function. A closure—unlike a plain function pointer—allows a function to access those non-local variables even when invoked outside of its immediate lexical scope.

In other words, a closure combines both the function and its containing environment, and stores references to the variables declared in its parent scopes. When the function is called, it can access those variables regardless of where the call site is.

Take a look at how this looks in JavaScript:

[edit] Basic example

Here is a basic example of a closure:

function Person(name)
{
    this.introduce = function()
    {
        console.log("Hello, my name is %s", name);
    }
}
 
// create an instance of Person:
var someone = new Person("Arthur");
 
// we call a closure!
someone.introduce(); // prints "Hello, my name is Arthur"

someone.introduce is a closure because this function uses a variable outside its own scope (notice that there is no name variable inside the introduce method).

It is notable that, where someone.introduce is called in the above example (i.e. its call site), the name variable can not be accessed by any regular means. This is where the Closure Inspector comes in.

[edit] Closure Inspector

[edit] Using the Command Line

The syntax to access the closure variables is as follow:

closure.%variable

In the above example, you would access name using this expression:

someone.introduce.%name // ==> "Arthur"

Note that you can also change values:

someone.introduce.%name = "Trillian";
someone.introduce(); // prints "Hello, my name is Trillian"

The same syntax works everywhere in Firebug where JavaScript is required, such as in the Watch Panel and conditional breakpoints.

[edit] Using the DOM/Watch panels

In order to see closures in the DOM/Watch panels, you need to activate the "Show Closure" option:

Activate Show Closure.png


You can then access closure variables of a function by expanding its magic (closure) property:

Access Closure Variables.png


[edit] Tips

[edit] Prevent the browser from optimizing away variables or closures

The browser often optimizes away the values of variables that are not used, or that only need to live for the duration of a call. Similarly, functions that don't refer to anything in their containing environment do not get treated as closures. There is no way for Firebug to prevent this from happening (even if it was possible, it would cause large performance regressions and memory leaks).

If you do need to keep one of these references to watch its value, you can temporarily modify the source code to include an eval("") nearby. (Like with, direct eval calls disable much of the optimization JavaScript engines can do.) Here is an example:

function modularCycle(start, modulo)
{
    var cur = start % modulo;
 
    // prevents ''start'' from being optimized away:
    eval("");
 
    return function(addition)
    {
        cur = (cur + addition) % modulo;
        return cur;
    };
}
 
var cycle = modularCycle(42, 30);
cycle(20);
 
// using the command line:
cycle.%start; // ==> 42 (would print "(optimized away)" without the ''eval'' call)

Remember to remove it afterwards, as it can be a source of performance penalties or memory leaks.

[edit] Shorthand

Considering the basic example, in order to access to name, you type the following:

someone.introduce.%name;

As a handy shortcut, you can also use someone.%name to do the same thing. When Firebug encounters such an expression a.%b where a is not a function, it will look up the first member function of a which is a closure and use closed-over variables from there. In other words, these two syntaxes are equivalent:

someone.%name;           // ==> "Arthur"
someone.introduce.%name; // ==> "Arthur"

[edit] Getters and setters

Consider the case where the functions you are interested in are getters or setters on some object:

function Person(birthYear)
{
    Object.defineProperty(this, "age", {
        get: function()
        {
            return new Date().getFullYear() - birthYear;
        }
    });
};
 
var person = new Person(1970);

Then there is unfortunately no direct way of accessing birthYearperson.age.%birthYear does not work (it tries to get a closure variable of an integer). In such cases, you will have to use Object.getOwnPropertyDescriptor (or the deprecated __lookupGetter__):

Object.getOwnPropertyDescriptor(person, "age").get.%birthYear; // ==> 1970
person.__lookupGetter__("age").%birthYear;                     // ==> 1970

The shorthand version person.%birthYear might also work.

Personal tools