JAVA SCRIPT - Creating a Function That Remembers Its State

Creating a Function That Remembers Its State


Problem

You want to create a function that can remember data, but without having to use global variables and without resending the same data with each function call. 

Solution

Create an outer function that takes one or more parameters, and then an inner function that also takes one or more parameters but uses both its and its parent function’s pa‐ rameters. Return the inner function from the outer function, and assign it to a variable. From that point, use the variable as a function:

function greetingMaker(greeting) {
 function addName(name) {
 return greeting + " " + name;
 }
 return addName;
}
// Now, create new partial functions
var daytimeGreeting = greetingMaker("Good Day to you");
var nightGreeting = greetingMaker("Good Evening");
...
// if daytime
console.log(daytimeGreeting(name));
// if night
console.log(nightGreeting(name));


EXPLAIN 


We want to avoid cluttering up the global space with variables, as much as possible. However, there are times when you need to store data to be used across several function calls, and you don’t want to have to repeatedly send this information to the function each time. A way to persist this data from one function to another is to create one of the functions within the other, so both have access to the data, and then return the inner function from the outer.

Returning one function from another, when the returned function is using the outer function’s scope, is known as a function closure. Before I get into the specifics of function closure, I want to spend a few minutes on functions and scope. In the solution, the inner function add Name() is defined in the outer function greeting Maker(). Both of the functions have one argument. The inner function has access to both its argument and the outer function’s argument, but the outer function cannot access the argument passed to the inner function.

The inner function can operate on the outer function’s parameters because it is operating within the same context, or scope, of the outer function. In JavaScript, there is one scope that is created for the outermost application environ‐ ment. All global variables, functions, and objects are contained within this outer scope. When you create a function, you create a new scope that exists as long as the function exists.

The function has access to all variables in its scope, as well as all of the variables from the outer scope, but the outer scope does not have access to the variables in the function. Because of these scoping rules, we can access window and document objects in all of our browser applications, and the inner function in the solution can also access the data passed to, or originating in, the outer function that wraps it. However, the outer function cannot access the inner function’s arguments or local data because they exist in a different scope.

When a function returns a function that refers to the outer function’s local scope:


function outer (x) {
 return function(y) { return x * y; };
}
var multiThree = outer(3);
alert(multiThree(2)); // 6 is printed
alert(multiThree(3)); // 9 is printed


The returned function forms a closure. A JavaScript closure is both a function and an environment that existed at the time it was created. In addition, the example also dem‐ onstrates partial application, where a function’s arguments are partially filled (our bound) before it’s executed. When the inner function is returned from the outer function, its application scope at the time, including all references to the outer function’s variables, persist with the func‐ tion. So even though the outer function’s application scope no longer exists, the inner function’s scope exists at the time the function was returned including a snapshot of the outer function’s data. It will continue to exist until the application is finished.


So what happens to these variables when an application scope is released? JavaScript supports automatic garbage collection, which means that you and I don’t have to man‐ ually allocate or deallocate memory for our variables. Instead, the memory for variables is created automatically when we create variables and objects, and deallocated auto‐ matically when the variable scope is released. In the solution, the outer function greetingMaker() takes one argument, which is a specific greeting. It also returns an inner function, addName(), which itself takes the person’s name. In the code, greetingMaker is called twice,

once with a daytime greeting, assigned to a variable called daytimeGreeting, and once with a nighttime greeting, assigned to a variable called nightGreeting. Now, whenever we want to greet someone in daytime, we can use the daytime greeting function, daytimeGreeting, passing in the name of the person. The same applies to the nighttime greeting function, nightGreeting.

No matter how many times each is used, the greeting string doesn’t need to be re-specified: we just pass in a different name. The specialized variations of the greeting remain in scope until the application terminates. Closures are interesting and useful, especially when working with JavaScript objects, as we’ll see later in the book. But there is a downside to closures that turn up when we create accidental closures.


An accidental closure occurs when we code JavaScript that creates closures, but aren’t aware that we’ve done so. Each closure takes up memory, and the more closures we create, the more memory is used. The problem is compounded if the memory isn’t released when the application scope is released.

When this happens, the result is a per‐ sistent memory leak. Here’s an example of an accidental closure:

function outerFunction() {
 var doc = document.getElementById("doc");
 var newObj = { 'doc' : doc};
 doc.newObj = newObj;
}
The newObj contains one property, doc, which contains a reference to the page element identified by doc. But then this element is given a new property, newObj, which contains a reference to the new object you just created, which in turn contains a reference to the page element.

This is a circular reference from object to page element, and page element to object. he problem with this circular reference is exacerbated in earlier versions of IE, because these older IE versions did not release memory associated with DOM objects (such as the doc element) if the application scope was released.

Even leaving the page does not reclaim the memory: you have to close the browser. Other browsers and newer versions of IE detect this type of situation and perform a cleanup when the user leaves the application (the web page where the JavaScript resided). However, function closures should be deliberate, rather than accidental.

0 comments:

Post a Comment