Created
July 17, 2011 18:53
-
-
Save robotlolita/1087927 to your computer and use it in GitHub Desktop.
Attempt at explaining closures number 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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