This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 8 years ago.
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gAlertNumber = function() {console.log(1); alert(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
how can I accesss here gAlertNumber method?
update: this code is the Example 4 in an answer on How do JavaScript closures work?
Assuming you're in a web browser, you have to execute setupSomeGlobal() first.
Then your non-declared handler variables g... will be created under the global object window and you'll be able to execute gAlertNumber() from anywhere in your page.
You could execute setupSomeGlobal() in the body's onload :
<html>
<head>
<script>
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gAlertNumber = function() {console.log(1); alert(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
</script>
</head>
<body onload="setupSomeGlobals();">
<input type="button" value="Show me more or less the number of the beast" onclick="gAlertNumber();"
</body>
</html>
That said, your method of setting up "global" functions isn't very pretty.
I quite like the pattern described here for example.
Here is an example,
(function() {
console.log(1);
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() { console.log(num); }
num++;
return sayAlert();
})();
This will call immediately after definition.
So with your code,
function setupSomeGlobals() {
var num = 666;
// Store some references to functions as global variables
gAlertNumber = function() {console.log(1); alert(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
gAlertNumber();
}
setupSomeGlobals();
Here you can call the child function gAlertNumber() inside your parent function setupSomeGlobals() and you cannot access it outside the parent function.
But you can call this after calling parent function, that means don't call the gAlertNumber() inside parent function. call it after calling parent like,
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gAlertNumber = function() {console.log(1); alert(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
setupSomeGlobals();
gAlertNumber();
Return an object from setSomeGlobals() that contains the three methods. Through this object you will be able to access the functions of interest and manipulate num and keep its state, but you will not be able to access num directly. This is known as the module pattern, an application of closure.
Well this will work in browser
gAlertNumber is considered being window property.. It would be the same as calling
window.gAlertNumber()
so inside your setSomeGlobals you assign function object to the undefined window property. Than you close the local variable num inside that object which is already created inside window object. Thus you can access it from window scope.
Related
Any function within function forms a closure. Do closures always needs to be in an immediately invoked function?
The first example is where a closure is formed within an iife and works as expected, gives "8" and "7" as output.
var cat = (function (){
var lives = 9;
return function() {
return --lives;
}
}());
console.log("iife");
console.log(cat());
console.log(cat());
In the below example the closure does not work as expected, prints the same value every time.
var cat = function (){
var lives = 9;
return function() {
return --lives;
}
};
console.log("no iife");
console.log(cat()());
console.log(cat()());
A closure is just the link between a function and the scope in which it was created, link which exists when the function uses a variable from this scope.
You have this problem because you don't keep the closure: you're recreating it at every console.log when you call cat().
Change
console.log(cat()());
console.log(cat()());
into
let c = cat();
console.log(c());
console.log(c());
If I create a callback within a function, can I get that callback to access the local variables within that function?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
callback();
}
Obj.prototype.innerFunc = function()
{
x++;
}
x naturally is not within the scope of innerFunc and will produce an error if called by itself. But if I call it from outerFunc can I extend innerFunc's scope in order to access x?
Edit: Should've mentioned that I don't want to pass arguments into the function or make x and instance of Obj. I'm more looking to treat innerFunc as though it was declared locally in outerFunc. Similar to what can be done below:
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = function() {
x++;
}
callback(); // works
}
Yes: this is exactly what function parameters are for. They allow you to pass a value from one scope into another.
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
x = callback(x);
}
Obj.prototype.innerFunc = function(x)
{
x++;
return x;
}
Note that the value is sent to the other function, not the variable. So you need to return the value and assign it in order to use it.
If you're using prototypes, just set an instance property:
// constructor
var Obj = function () {}
Obj.prototype.outerFunc = function()
{
this.x = 0;
var callback = this.innerFunc.bind(this);
callback();
}
Obj.prototype.innerFunc = function()
{
this.x++;
}
var instance = new Obj()
instance.outerFunc()
console.log(instance.x) // returns 1
Edit: But #lonesomeday's answer is a much better solution as it takes a more functional approach avoiding side effects :)
The preffered way of doing this is to assign x to the scope of the object then all functions can access it, via this.x
Obj.prototype.outerFunc = function()
{
this.x= 0; // set x to zero
this.innerFunc();
}
Obj.prototype.innerFunc = function(x)
{
this.x++;
return this.x;
}
This is a bit hard to solve without knowing why you don't want to pass a parameter; if you just want to have a specific function signature, maybe a higher-order function might help?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc(x);
callback();
}
Obj.prototype.innerFunc = function(x)
{
return function () { /* use x in here */ };
}
This way you have two functions one inside the other. The outer one takes the parameter, and the inner one can access the variable that is passed to the outer one.
This of course only gives you half of what you demonstrate in your example: You can access the local variable but not modify it.
You can never access any function's internal variables from outside the function under any circumstances, in an OOP context or otherwise.
The only sort-of-exception is that a function A defined inside a function B, and returned from that function B, continues to have access to the variables in function B--the basic notion of closure.
I have no idea why you don't want to use instance variables. That's what they're for--sharing data across methods. I have no idea why you don't want to pass values in or out--that's what parameters and return values are for.
can I extend innerFunc's scope in order to access x?
No, you can't, whatever that means. There is no such notion in JS.
The closest you can come to what you seem to maybe want to do is to define the variable in the constructor:
function Obj() {
var x = 0;
this.outerFunc = function() {
var callback = this.innerFunc;
callback();
};
this.innerFunc = function() {
x++;
}
}
However, this will not work as-is because this.innerFunc is missing its context. Therefore, you would need to write
var callback = () => this.innerFunc();
However, it's a mystery why you would want to do this instead of just writing this.innerFunc().
function emergency() {
var ambulance = 100;
var callAmbulance = function() { alert(ambulance); }
ambulance++;
return callAmbulance;
}
var accident = emergency();
accident(); // alerts 101
I am referring to the variable 'ambulance'.
When I call accident(); it should call emergency() which should use the declared variable 'ambulance' [considering the global scope thing in javascript, still it could set the value to global] but its using old value 101 instead of setting again back to 100 - behaving more like static var.
What's the Explanation?
What you have there is called a closure. It means a function can access variables declared in outer functions (or in the global scope). It retains access even after the 'parent' function has returned. What you need to understand is that you don't get a copy. The changes performed on that variable are visible to your inner function, which in theory means you could have multiple functions sharing access to the same variable.
function f () {
var x = 0;
function a() { x += 1; }
function b() { x += 2; }
function show() { console.log(x); }
return {a:a, b:b, show:show};
}
var funcs = f();
funcs.a();
funcs.b();
funcs.show(); // 3
One thing to be aware of is that a subsequent call to f will create a new scope. This means a new x variable will be created (new a, b, show functions will be created as well).
var newFuncs = f();
newFuncs.a();
newFuncs.show(); // 1
funcs.a();
funcs.show(); // 4
So, how do you get a copy? Create a new scope.
function g () {
var x = 0;
var a;
(function (myLocal) {
a = function () { myLocal += 1; }
}(x));
x += 200;
return a;
}
JS only has pass-by-value so when you call the anonymous function, the xvariable's value will be copied into the myLocal parameter. Since a will always use the myLocal variable, not x, you can be certain that changes performed on the x variable will not affect your a function.
If, by any chance, you're coming from a PHP background you are probably used to do something like
use (&$message)
to allow modifications to be reflected in your function. In JS, this is happening by default.
You are creating a function definition which is not compiled at this time:
var callAmbulance = function() { alert(ambulance); }
And before you are sending it to the called function, you are incrementing the num:
ambulance++;
And then you are sending it to the called function:
return callAmbulance;
But whether you are sending it there or not, it doesn't matter. The below statement executes or compiles the function:
var accident = emergency();
And this takes in the current ambulance value which is 101 after the increment. This is an expected behaviour in creating function but not executing it. Please let me know, if you didn't understand this behaviour. I will explain it more clearly.
Is there a way to print the value of temp (a closure variable) from a function defined outside the closure but referenced within the closure without passing temp as a variable to funcA?
var funcA, funcB;
funcA = function () {
console.log(temp);
}
funcB = function () {var temp, funcC;
temp = 1;
funcC = funcA;
funcC();
}
funcB(); // temp is undefined.
This works, but only because funcA is defined within funcB:
funcB = function () {var temp, funcA, funcC;
temp = 1;
funcA = function () {
console.log(temp);
}
funcC = funcA;
funcC();
}
funcB(); // 1
I'm trying to find a way to pull some function definitions out of outer functions to streamline code that's getting a little complex. Can I define funcA outside of funcB but still reference the temp variable without having to pass parameters?
I read that javascript does not have dynamic run time scoping, that it's only lexical scoping, but with referencing a function (funcA via funcC) within funcB, is there a way to meet the lexical scope requirement and provide access to the scoped variables for funcB?
Using Akinkunle Allen's comment, I came up with this which seems to solve my problem.
function funcB () {
var funcA, funcB, temp;
funcA = function () {
console.log(temp);
}
funcB = function () {var funcC;
temp = 1;
funcC = funcA;
funcC();
}
return funcB();
}
funcB(); // 1
Yes, and No.
The keyword var for declaring variables behaves different depending upon what the current scope is. When var is executed on the global scope it is optional. The variable becomes a property of the global object. When executing in the browser this global object is window.
So the following in global space has the same result.
var temp = 1;
window.temp = 1;
this.temp = 1;
All the above is just window.temp because of the global context.
When you use var inside a function then the variable is attached to the function. All functions in Javascript are objects so local var variables will live as long as the parent function is still being used somewhere.
Javascript will walk the hierarchy of executing scopes to find a variable identifier. So any inner functions can access their outer function variables (as in your example).
What you can do is play around with the this reference in functions.
The identifier this in Javascript is dynamic (meaning that you can change it). I can pass a variable to an unknown function that was declared outside the calling function. Since the this.temp is used to reference the variable the function funcA is able to display the value.
funcB = function(otherFunc)
{
this.temp = 1;
otherFunc();
}
funcA = function()
{
alert(this.temp);
}
funcB(funcA);
http://jsfiddle.net/thinkingmedia/dfLvj/
See the above jsfiddle example.
What you can do with this is change the meaning of this on the fly. Here is a better example.
funcB = function(otherFunc)
{
var temp = {
message: "Hello World!"
};
var foo = otherFunc.bind(temp);
foo();
}
funcA = function()
{
alert(this.message);
}
funcB(funcA);
http://jsfiddle.net/thinkingmedia/K5Pw6/
Dynamically changing this can have a lot of benefits by allowing a function to accept closure references that will be executed with a custom this reference.
An example might be a click event handler where this is the DOM element that triggered the event.
Refering to How do JavaScript closures work?.
Closure is:
a closure is the local variables for a function — kept alive after the function has returned, or
a closure is a stack-frame which is not deallocated when the function returns (as if a 'stack-frame' were malloc'ed instead of being on the stack!).
Just want to confirm are the following consider closure?
1) Binding javascript function within a function.
var Books = {
init:function(){
$('#box').bind('click',function(){
console.log('click');
});
}
};
Books.init();
2) Declare a function within a function
function sayHello(name) {
var text = 'Hello ' + name;
var sayAlert = function() { alert(text); }
}
var hello = sayHello();
I still can't differentiate which is closure for some times, is that all function within function consider closure or only the one that keep the returned inner function as variable/reference. Example:
function sayHello(name) {
var text = 'Hello ' + name;
var sayAlert = function() { alert(text); }
**return sayAlert;**
}
1 isn't as no variables are actually referenced, 2 and 3 are.
In 2 and 3 the variable called text is closed off - referenced outside its lexical scope. In 1 nothing is.
crockford on closures :
What this means is that an inner function always has access to the
vars and parameters of its outer function, even after the outer
function has returned.
All of those are closures.
I'm not sure what your confusion is.