Skip to content

Instantly share code, notes, and snippets.

@robotlolita
Created July 17, 2011 18:53
Show Gist options
  • Save robotlolita/1087927 to your computer and use it in GitHub Desktop.
Save robotlolita/1087927 to your computer and use it in GitHub Desktop.
Attempt at explaining closures number 1
// The idea is to understand this little piece of code, from Eloquent
function makeAddFunction(amount) {
function add(number) {
return number + amount;
}
return add;
}
var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));
// => 9
// Note that all stuff between square brackets is purely special/pseudo code, and it has nothing
// to do with JavaScript :3
// Functions are just objects that have an environment and a set of instructions.
// Therefore, you could define a function like this:
function = { environment: { }
, call: [executable-set-of-instructions] }
// An environment is just a pair of key/value defining the variables to which a
// function has access. It also includes the parameters that were passed into
// the function.
// Such that, if we have a function makeAddFunction(amount) and call it with
// argument amount = 2, we'll end up with the following environment
makeAddFunction: { environment: { amount: 2 }
, call: [executable-set-of-instructions] }
// Note that such environment is created anew whenever makeAddFunction is called.
// In fact, you could think of a function as a class, that defines which attributes
// it'll have, and how it'll apply transformations in those attributes
//
// To stay within javascript bounds, let's say that this resulting object from
// calling the function, have access to the properties defined in the environment
// throught the `this` name.
//
// You could rewrite the above example as:
makeAddFunction:
{ environment: { amount: undefined, add: undefined },
call: [executable-set-of-instructions, where:
this.amount = [passed-parameter amount]
this.add = { environment: { parent: makeAddFunction.environment, number: undefined }
, call: [executable-set-of-instructions, where:
this.number = [passed-parameter number]
return this.number + this.amount
]}
return this.add
]}
// As you see, the `add' function inside makeAddFunction is also created anew everytime
// makeAddFunction is called. Now, notice how its environments says that they have a `parent'.
//
// A parent environment is a pointer to an environment where we can look for names if we
// can't find them in the current environment.
//
// You could think about the `this.property' workings as this:
//
// 1. Check if `property' exists in the current environment
// 2. If found, return the property value.
// 3. Otherwise, set the current environment to the `parent' environment.
// 4. If the current environment doesn't exist, fail to find the property.
// 5. Otherwise, go back to 1.
// Now, that we have established that environments are just objects that map names to
// values, and which are tied to the functions, we can move on to the rest of the
// problem.
//
// Namely, the lines:
// var addTwo = makeAddFunction(2);
// var addFive = makeAddFunction(5);
//
// Remember that, when we call makeAddFunction with a parameter, it'll create an entirely
// new object, that will have two properties: `amount', whose value will be whatever we pass
// to the function, and `add', which will be a function object. A whole new one too, and only
// available to this makeAddFunction.
//
// So, when we say `var addTwo = makeAddFunction(2)', we're assigning the return of a new instance
// of makeAddFunction to addTwo. And this instance will have `amount = 2' in its environment.
// The return value is, obviously, the internal `add' function, which is also a new instance, whose
// environment now points (and has total access to) the environment tied to `makeAddFunction', and in
// turn, all the values that are defined in there (we're interested in the `amount = 2' now).
//
// The other line, `var addFive = makeAddFunction(5)' works the exact same way, with the only difference
// that addFive's environment has `amount = 5' instead of `amount = 2'. Remember, they're different objects
// so one does not affect the other.
// Then, in the last line:
// show(addTwo(1) + addFive(1));
//
// We call the objects we stored in both addTwo and addFive. That is, the instance of `add' that was created.
// As those objects have access to the environment that was defined in makeAddFunction at the time it was
// called, they remember what `amount' means. It means `2' for addTwo, and `5' to addFive. They can work
// with those values, and can manipulate them, as if such code was running in the `makeAddFunction' itself.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment