Determine the set of variables accessible within a JavaScript closure - javascript

"[JavaScript functions] internally store any variables they may refer to that are defined in their enclosing scopes."
How can I determine what that set of variables is?
For example, David Herman in Effective JavaScript gives this function (and closure):
function sandwichMaker() {
var magicIngredient = "peanut butter";
function make(filling) {
return magicIngredient + " and " + filling;
}
return make;
}
var f = sandwichMaker();
document.writeln("<p>" + f("jelly") + "</p>");
document.writeln("<p>" + f("bananas") + "</p>");
document.writeln("<p>" + f("marshmallows") + "</p>");
Sure, magicIngredient is a variable accessible to make(), but what else is? What if sandwichMaker were itself within a function? And then there are the globals. What is the function looking at when it looks for relevant values within the current scope?

What if sandwichMaker were itself within a function? And then there are the globals.
Yes, all the variables from parent functions are accessible (if they are not shadowed). And the highest-scoped function inherits from the global scope then.
What is the function looking at when it looks for relevant values within the current scope?
You can inspect that with a debugger. Insert a debugger; statement in make, and then execute it and have a look into your devtools. You will see something like this:
Scope Chain
0. make (currently executed):
this: (+)Window
arguments: (+)Arguments
filling "jelly"
1. sandwichMaker:
arguments: (+)Arguments
magicIngredient: "peanut butter"
make: (+)Function
Global
AnonXMLHttpRequest: …
ApplicationCache: …
Array: …
…
Also have a look at this great article: http://dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/
Example view at Chrome Devtools:
(from www.briangrinstead.com):

JavaScript uses function scope. This is pretty simple to understand - anything declared in a function has scope to that function as well as any higher scopes.
A closure can be thought of as two things being combined together: a particular scope, and a particular point in time (when the function was created).
Sure, magicIngredient is a variable accessible to make(), but what
else is?
Anything that was accessible to the scope of make at the time it was created. This includes all variables in the make function as well as any higher scopes. The scope of make is said to be closed-over the scope that existed at the point in time it was created, always giving it access to magicIngredient.
What if sandwichMaker were itself within a function?
Then make would have access to that scope (as it existed at the time make was created) as well.
And then there are the globals. What is the function looking at when it looks
for relevant values within the current scope?
The interpreter will search the currently executing scope for any referenced variables. If it can't find them, it will look in the next higher scope. It will continue looking higher and higher until it finds the variable or runs out of scopes (the global scope is the highest, aka the window object for javascript running in a browser).
A related concept is shadowing - two variables can have the same name in parent/child scopes, the child is said to "shadow" the parent because it will take precedence. Note this is a bad practice.
The easiest way to understand how closures and scoping works is to understand a simple factory pattern, such as this one. When the inner function is created and returned, it is bound to that scope at that point in time and will continue to alert the proper values even after the values no longer exist.
Hope this helped - lots of questions stuffed into one question :)

Suppose above function sandwichMaker() there was a variable defined...
var something = 'something';
function sandwichMaker () {
...
You can access something from within sandwichMaker() AND from within make().
The outer variables are accessible from within the functions. If you were to set var something = 'something else' within make(), then you would be effectively hiding the outer var something while within the make() function itself. However, you can just set something = 'something else', and the value will have changed at all scopes. It only hides the value if you declare that variable again.

Related

Why is "reduce" and "map" considered closures in javascript?

I was going over closures and usually I look at a closure as a function that has been returned from another function or is a function that is set to a global while inside another function so that the new function (returned function or global variable) has a reference to the variables inside the initial enclosing function where it was created. Recently, someone told me that the map or reduce function form closures. These return a value or values and no function whatsoever. I dont see how this method forms a closure when all you have is a callback. In fact, MDN states that the reduce function returns a "value" and the map function returns an array. So where is the closure? Can someone explain this?
A function defined inside a function ends up being a closure by definition if local variables are present at the surrounding function and they're used inside the closure.
For example:
function boil(ocean) {
var boiling = 100.0;
return ocean.map(function(h2o) {
return h2o.temp >= boiling ? 'vapour' : 'water';
});
}
The boiling variable here is defined in the main function and used within the function passed to map. Callback functions make the closure behaviour more obvious since they're used in a different context, but the same principle applies.
The "closure" is the callback function. According to MDN:
A closure is the combination of a function and the lexical environment within which that function was declared.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
So when you write something like this:
array.map(function(object) {
// do something
});
That function that you pass in becomes a closure because it gains access to the scope that was present when array.map was called. That's just how JavaScript works.
Thank you all for your responses to the question. With these and the chrome debugger I have come to the conclusion. As Alnitak stated, "
It's a closure iff it accesses variables from that outer scope. Just having the ability to access them is insufficient." This is an important point that I was missing. Also, you can see in the scope section of the sources tab in chrome debugger variables included through closure. So, looking at the following example we can see exactly what closure is:
routerAction: function () {
var name = "alex";
var alex = function(v){
debugger;
console.log("this is var ", name);
}
alex(); // if name was passed and then printed it would be local
// not a closure
}
Functions get their scope from global and local and closure variables.
When you pass "name" into the alex function as a parameter it becomes a local variable so there is no closure. So, if I passed it to alex and console logged "v" where name is, no variables are referenced through a closure. However, since name is defined outside the scope of function alex and then used within, it is scoped through closure (this can be seen in in the scope section of the chrome debugger). By this same logic, if the array that you are operating on (using map or reduce )is defined inside a function, the callback has to form a closure iff the array is referenced inside the callback. If the parameters are just brought in through arguments, none of the variables are accessed through a closure, they are all local variables.

Javascript - understanding the scope chain's reference priority

I would like to better understand the scope chain the hopefully closure better and so the following code:
function greet(whattosay){
return function(name) {
whattosay = "not hi"; //change the hi message
console.log(whattosay + ' ' + name);
function insideAnon() {
console.log(whattosay);
}
}
}
var sayHi = greet('Hi'); //get in return the anon function
sayHi("John"); //print not hi John on the console
I have recently learned that every "variable environment" is actually an array or an object with properties, and so each function has a reference to it's parent's function variable environment object/array. But my question is, what exactly is the scope chain?(I know that it is supposedly going "down" up until the global level), My current perception (Not sure) is that each child has it's parent and grandparent (and so on) variable environment references inside of it, and so it first check it's parent's variable environment object, if a variable is not there it looks at it's grandparent's reference and so on. Or is it more like - Check the parent variable environment object reference, if not there that parent checks his parent's reference and so on. I HOPE i was very clear at what I was trying to say - How it really goes down the "chain".
You can get references about scope chains from this question:
Scope Chain in Javascript
Each function creates a scope object that contains the arguments for that function and the local variables defined in that function.
Since Javascript uses lexical scoping, that means that a given piece of code can access variables defined within the current function or within any parent function. Javascript makes this work by maintaining a chain of scope objects so each scope has a reference to its parent scope.
When a given piece of code accesses a variable like:
foo = 1;
Javascript, looks in the current scope object to see if something named foo exists there. If so, that variable is used. If not, it gets the reference to the parent scope, checks that scope for something named foo and continues this process up the parent chain until it gets to the global scope and thus can go no further.
So, in this example:
function one() {
var foo = 2;
function two() {
var fee = 3;
function three() {
foo = 1;
}
three();
}
two();
}
one();
The function one() will execute and define foo and two in its scope. It will then call two() which will execute and define fee and three in its scope. It will then call three() which will execute and attempt to change the value of foo. It will first look in the scope object belonging to three, but it will not find anything named foo there so it will go to the parent scope of three which will be the two scope object. It will not find a variable named foo in that scope object so it will go to the parent object of two which will be the scope object of one. There it will find a variable named foo so it will change the value of that variable.
On thing that is different about Javascript scope objects compared to something like a C++ stack frame is that they can continue to live after the function that created them has finished executing. This is a very common structure in Javascript and is often referred to as a closure. Here's a simple example of that:
function initializeCntr() {
var cntr = 0;
document.getElementById("test").addEventListener("click", function(e) {
++cntr;
document.getElementById("clickCnt").innerHTML = cntr;
});
}
initializeCntr();
In this short code example, there are three scopes present, the global scope (that contains the initializeCntr symbol), the initializeCntr scope that contains the cntr variable and the scope that belongs to the anonymous function that is set as the event handler.
When you call initializeCntr(), it creates a function scope object that contains the variable cntr. It then runs the addEventListener() method and passes a reference to the inline anonymous event handler for addEventListener(). The initializeCntr() method then finishes execution. But, because the inline anonymous function passed as the event handler contains a reference to the cntr variable in the initializeCntr scope object, that scope object is NOT garbage collected even though initializeCntr() has finished executing. Instead, it is kept alive because of the lasting reference to the cntr variable in it. When that click event handler is then called sometime in the future, it can use that cntr variable. In fact, the initalizeCntr scope will be kept alive as long as the event handler is active. If the event handler is removed or the DOM object it is attached to is removed, then and only then would the initializeCntr scope object be eligible for garbage collection and eventually get freed.
Some JS implementations are smart enough to not necessarily retain the entire scope object and everything in it, but instead to only retain the elements of the scope object that are specifically referenced in child scopes that are still active. So, if there were other variables next to cntr that were not used in the event handler, those other variables could be freed.
FYI, this longer lasting scope is called a closure. Closures are very useful concepts in Javascript and something not available in a language like C++ (because they rely on garbage collection).

eval calls function which calls eval which defines function

I know the title sounds convoluted, but to keep things dynamic there is a purpose for this rest assured ;)
Examples (note that these example codes are assumed to be within an outer eval)
//Ex1 this works
eval('function test (){}');
test();
//Ex2 this doesn't work (myfunction definition is written below)
myfunction();
test(); //I get an error
If I defined myfunction globally (outside of the outer eval) I get this error: object is not a function
If I defined myfunction within the outer eval I get this error: object is not a function
//myfunction definition
function myfunction () {eval('function test (){}');}
Question is: how do I expand the scope of a function definition to just outside of the function it was defined within? I know about making an eval global (see alternate myfunction below), but that seems like overkill, I just want to increase the scope to the outer eval is all. Is this possible?
Update:
The examples only define one function to keep is simple, but I wish expand it so that myfunction defines many functions, and what functions it defines is dynamic depending on other factors. Also I wish to retain the function names as well as the definitions. I may end up just putting the contents of myfunction into the outer eval if I can't find a solution other than making eval call globally, then I have to copy over the contents to everyplace that uses it.
//making eval global works, but I had hoped to just upscope to the calling eval
function myfunction(){var globaleval=eval;globaleval('function test(){}');}
Below has been edited since the initial question:
Maybe you could make a var in outer eval, have myfunction return the address of the function definition to that var. However, I wish to retain the function names as well as the definitions.
OK, so I am assuming you actually mean you want to control the scope in which eval uses...
Why not
eval.call(context, 'function test(){}');
example
eval.call(window, 'function test(){}');
eval() does execute within the local scope but that isn't your problem.
First, ditch eval()!
Second, think clearly on what you want without eval(). Even better please update the question when you have that.
Since I can't understand the actual question here are some guesses:
1. Reference to a particular object
If you want a reference to this of a particular object and the current context isn't sufficient Then use something like this question to "bind" (included in ecma 5) your new function to this.
You'll still have reference to the local closure of course.
2. Function that has a specific closure
If you want to call a function whose scope is "further out" or different than your "current scope" then define "that function" in the scope you want it to have (the closure) but then use a reference to "that function" that inner scope has
e.g.
var test='outer';
var outer = function (){ alert(test);}
(function(){
var test='inner';
var inner = function(){
alert(outer());
}
inner();
})()
You'll note that inner() returns "outer" in this example
in your second example function test() doesn't exists, because it's not defined yet )))

javascript closure advantages?

Whats the main purpose of Closures in JS. Is it just used for public and private variables? or is there something else that I missed. I am trying to understand closure and really want to know what are the main advantages of using it.
Closures have to do with how javascript is scoped. To say it another way, because of the scoping choices (i.e. lexical scoping) the javascript designers made, closures are possible.
The advantage of closures in javascript is that it allows you to bind a variable to an execution context.
var closedIn = {};
var f = function(){
closedIn.blah = 'blah'; // closedIn was just "closed in" because I used in the function, but it was defined outside the function.
}
in that example, you have a normal object literal called closedIn. It is accessed in a function. Because of that, javascript knows it has to bring closedIn everywhere it brings the function f, so it is available to f.
The this keyword is tricky. this is always a reference to the execution scope. You can capture the this of one context to use in another context as follows:
var that = this;
var f = function(){
that.somethingOnThat();
// `this` means the scope f, `that` means whatever 'this' was when defined outside of the function
}
This trick can be very useful somethings, if you are coding object oriented javascript and want a callback to have access to some external scope.
To quote from a Javascript book:
"Functions in JavaScript are lexically
rather than dynamically scoped. This
means that they run in the scope in
which they are defined, not the scopee
from which they are executed. When a
function is defined, the current scope
chain is saved and becomes part of the
internal state of the function."
So the clear advantage is that you can bring any object (functions, objects, etc) along with the scope chain as far as is necessary. This is can also be considered a risk, because your apps can easily consume lots of memory if you are not careful.
I think the best phrase to sum up the purpose of closures would be:
Data Encapsulation
With a function closure you can store data in a separate scope, and share it only where necessary.
If you wanted to emulate private static variables, you could define a class inside a function, and define the private static vars within the closure:
(function () {
var foo;
foo = 0;
function MyClass() {
foo += 1;
}
MyClass.prototype = {
howMany: function () {
return foo;
}
};
window.MyClass = MyClass;
}());
Closures are necessary in javascript due to the fact that most API's that require callback functions (for instance, an "onclick" function) do not provide other mechanisms to send parameters to those callback functions (or to explicitly set the "this" pointer). Instead, you need to use closures to allow the callback to access variables in the "parent" function.
I personally wish that they weren't necessary, since they can be hard to understand, make for hard to read code (it's not always clear what exactly is in scope), and make for weird bugs. Instead I wish there was a standard for callbacks that allowed you to send parameters, etc. But I accept that I am in the minority in this view.
As we know, the variables that are defined in functions, have local scope. We can't access them from outside of the function.
Problem 1:
local variables are created when the function is called and they will be destroyed when the function's task is finished. It means local variables have shorter life time than global variables. We may use global variables to overcome that issue.
Global variables are available when the program starts and are destroyed when it ends. They are also available throughout the program.
Problem 2:
Since global variables are accessible throughout the program, they are prone to change from everywhere.
What do we want?
We want to have data persistency + data encapsulation.
We can achieve them by using Closures. By using a closure we can have private variables that are available even after a function's task is finished.
Example:
function initCounter() {
let counter = 0;
return function () {
return ++counter;
}
}
// Each counter is persistent
const countJumps = initCounter();
countJumps();
countJumps();
alert("Jumps count is: " + countJumps());
const countClicks = initCounter();
countClicks();
countClicks();
countClicks();
countClicks();
alert("Clicks count is: " + countClicks());
// Each counter is isolated
alert(counter); // Error: counter is not defined

Distinguishing closure and local variables

A local function in the closure declares a variable with the same name which exists in the closure. So, how could we access closure's variable from the local function?
function closure()
{
var xVar;
function func1()
{
var xVar;
// how to distinguish local and closure scopes.
return xVar;
}
return function () { return func1(); };
}
Creating a private object and making private variables as properties of this object could help. But I am wondering if there is a better and neat solution. Can a scope chain help?
I have edited to make it a complete closure. Anyway, closures are not much concern here, it could be considered for inner functions however, there may be a solution with closures somehow.
Thanks
You can't access the scope chain explicitly in JS. Your problem is the age-old one of variable shadowing, but it's that much more maddening because in JS, the scope chain is actually there at runtime, it's just not available for you to access.
You can play some tricks with rejiggering current scope if you use the hated with operator, but that (as well as arguments's caller/callee stuff) really just give you access to objects and functions with their properties. There's no way to say "give me what xVar means in the n-1 runtime scope from right here".
Variables defined in an inner scope hide variable declarations in an outer scope. The "better and neat solution" is not to reuse variable names that way.
In your example the xVar variable is not a closure, because you redefined its scope to each function. To use that variable as a closure continue to declare it with the var command in the closure() function and then do not declare it with the var function in the func1() function. Instead just use the variable immediately in func1().
There is not an easy way to test if a function is a closure or a local variable. You would have to perform some sort of flow control test and then analyze assignments, where assignments occur, and where assignments do not occur. Then you must compare those results. You could write a tool, in JavaScript, to perform that analysis upon a given input and write you a report as output.

Categories

Resources