I am trying to understand closures.
var a = 1;
var g = function () {
var a = a;
return function() {
console.log(a);
}
}
g()();
As far as I know, the function invocation g()() should log the value of a, i.e. 1. But it is logging undefined on the console. I know my concept is weak somewhere, but am not able to figure out even after spending few hours. Can someone help?
JavaScript hoists var declaration in the entire function scope. The variable from the outer scope var a = 1 is overwritten.
The example is equivalent to this:
var a = 1;
var g = function () {
var a; // a is undefined
a = a; // a = undefined
return function() {
console.log(a);
}
}
g()();
Without initial value assignment, a is simply undefined. Later you assign the variable to itself a = a, which is a noop and a remains undefined.
For more information about variables hoisting, check this article.
The problem is the line
var a = a;
This is both declaring a locally scoped variable and assigning it to itself - it's not interacting with the global a. You need to use a differently named local variable:
var a = 1;
var g = function() {
var b = a;
return function() {
console.log(b);
}
}
g()();
Related
i'm a beginner in javascript and i tried to learn about function that called inside a function which redefine a value of a variable. Here's the code
var a;
function app2(a) {
var a = 8;
return a
}
function app(a) {
var a = 7;
app2(a)
return a
}
console.log(app(a));
when i run code, it still show 7 as the output. i thought it will be 8 because i've called the function app2 in the app function. why the value doesn't change into 8? and what should i do update the variable value inside the nested function? thanks in advance
1) You can only get 8 if you are taking the value of app2 and using it inside app.
Variables declare with var keyword are function scoped and they are not visible outside of that particular function in which it is declared.
a declared in app2 is not visible inside app unless you are not returning the value from app2 and not using the return value from app2 inside app(Both condition should be satisfied to use it)
var a;
function app2(a) {
var a = 8;
return a;
}
function app(a) {
var a = 7;
a = app2(a); // reassign the returned value from app2
return a;
}
console.log(app(a));
2) If you are returning it and not capturing it, then It's no use. You can also do as:
var a;
function app2(a) {
var a = 8;
return a;
}
function app(a) {
var a = 7;
return app2(a); // Directly return the value of app2 returned value
}
console.log(app(a));
I think the main culprit of what you are seeing is that you are naming the arguments of the functions a and also the global is named a.
When experimenting with this you would expect a = 8 when all var keywords are removed except for the global one. This does not happen because the argument, named a, is shadowing the global var a. When you use the var keyword locally in a function you are essentially telling javascript you want to declare a local function-scoped var a, and not reference the global var a, so this way any changes stay in the function scope.
Check this snippet out:
var a;
function app2(b) { // changed argument name from `a` to `b`
a = 8; // removed var keyword here
return a
}
function app(b) { // changed argument name from `a` to `b`
a = 7; // removed var keyword here
app2(a)
return a
}
console.log(app(a)); // output: 8
I've been told that javascript variables should all come before they are used in a function, such that:
function contrived() {
var myA, myB;
myA = 10;
myB = 20;
return myA + myB;
}
Is prefered over:
function furtherContrivance() {
var myA = 10;
var myB = 20;
return myA + myB;
}
Is this the case? And why is that?
I guess some people might prefer the former style because that's how it works inside. All local variables exist for the entire lifetime of the function, even if you use var to declare them in the middle of the function.
There's nothing wrong with declaring variables later in the function, syntax-wise, it might just be confusing as the variables will then exist before the line that declares them. Hence this function:
function bar() {
alert(foo); // Alerts "undefined". Not an error because the variable does exist.
var foo = 10;
alert(foo); // Alerts the value 10.
}
Is equivalent to this:
function bar() {
var foo;
alert(foo);
foo = 10;
alert(foo);
}
Another related fact is that nested function definitions (done using function foo() { ... }) will get moved to the top of the containing function as well, so they will be available even if the code that calls them comes before them.
Yes, the variable declaration should come at the top of the function:
function foo() {
var a, b;
}
However, initializing variables can be part of the declaration:
function foo() {
var a = 10, b = 20;
}
The reasoning behind declaring all variables at the top of the function where they are used is to avoid scope confusion.
Here is an example of bad code:
function foo() {
var b;
for (var i = 0; i < 5; i++) {
var a;
a = b = i;
setTimeout(function(){
console.log(a, b);
}, 1000);
}
}
If you execute the code, it will log 4, 4 5 times, rather than counting up. This is because only functions act as closures and introduce new scope. In JavaScript, any var declaration within a function gets executed at the beginning of the function.
This makes the above error much more visible:
function foo() {
var a, b, i;
for (i = 0; i < 5; i++) {
a = b = i;
setTimeout(function(){
console.log(a, b);
}, 1000);
}
}
There is no difference in this case between this two. I'd go with:
function furtherContrivance() {
var myA = 10,
myB = 20;
return myA + myB;
}
which is knows as single var pattern in javascript.
What you really need to take care of is defining your variables in the beginning of your functions. There is a thing in javascript called variables hoisting which means that variable definitions used in function "raise" on top. It's best described by an example:
var x = 'global'; // global (bounded to a global object which is window in browsers)
function func() {
alert(x); // undefined (you expected 'global', right?)
var x = 'local';
alert(x); // local
}
func();
what really happens is called (as I said) variables hoisting (definition of x raises on top), so the code above is actually the same as:
var x = 'global';
function func() {
var x; // definition of `x` raised on top (variables hoisting)
alert(x); // undefined in a local scope
x = 'local';
alert(x);
}
What a javscript interpreter does is it looks inside a function, gathers locally defined variables and raises them on top - this might be a good reason why you should use single var pattern.
In the example you give this is absolutely not the case. In a language like Javascript, it will be more of a developer preference, but it won't have any impact on the result.
Yes, place them at the top. It adds to code clarity.
Try this example:
var x = 1;
(function() {
x++;
alert( x ); // What will this alert show?
var x = 'done';
alert( x );
})();
Looks like it should alert 2, but it alerts NaN.
This is because the variable declaration is hoisted to the top, but the initialization stays in the same place.
So what is actually happening is:
var x = 1;
(function() {
var x;
x++;
alert( x ); // What will this alert show? NaN
x = 'done';
alert( x );
})();
...which makes the NaN expected.
For readability, it's definitely preferred.
However, Javascript "hoists" declarations. Hoisting means that vars and functions will be automatically moved to the top of their scope. This allows you to do things such as use a function before it's declared:
function myScope()
{
test();
function test()
{
//...
}
}
This can lead to some confusion, especially if variables within block scopes are declared. For example:
for(var i in foo)
{
var e = myFunc();
}
The declaration of e will be hoisted to the top of the closure, and e will be initialized to undefined. This allows for some interesting non-intuitive situations, such as:
if(!foo) //Will not throw reference error because foo is declared already
{
var foo = {};
}
So, regardless of how you declare your variables, they'll all get "moved up" to the top of the function anyway.
Hope this helps!
I have a variable myVariable which is continuously changing. At some point I want to capture the value of myVariable (not a reference to myVariable) into another variable myVariableAtSomePoint.
Example code:
var myVariable = 1;
function test () {
var myVariableAtSomePoint= myVariable;
console.log(myVariableAtSomePoint);
}
myVariable = 2;
test(); // Prints 2, instead of 1.
You mention in your comments that myVariable is a number. Since myVariable houses a primitive type, simply use the code below:
myVariableAtSomePoint = myVariable;
Take a look at JAVASCRIPT: PASSING BY VALUE OR BY REFERENCE. Here's a quote:
When passing in a primitive type variable like a string or a number,
the value is passed in by value.
I would also suggest reading: How do I correctly clone a JavaScript object?
EDIT:
I believe that you're assuming that the placement of the function in the code affects the value of the variables. It does not. See examples below:
This:
function test () {
var myVariableAtSomePoint= myVariable;
console.log(myVariableAtSomePoint);
}
myVariable = 2;
test(); // Prints 2, instead of 1.
Is the same as this:
var myVariable = 1;
function test () {
var myVariableAtSomePoint= myVariable;
console.log(myVariableAtSomePoint);
}
myVariable = 2;
test(); // Prints 2, instead of 1.
Your problem is that you're changing the value of myVariable before you're assigning it to myVariableAtSomePoint. For this to work as you want, you'll need to call the test() function before you change the value of myVariable
var myVariable = 1;
function test () {
var myVariableAtSomePoint= myVariable;
console.log(myVariableAtSomePoint);
}
test(); // Prints 1
myVariable = 2;
test(); // Prints 2
IMPORTANT: No matter the placement of the function, the code inside test() is not executed until you call the function.
The variable only holds the reference and nothing else. If you want a copy of the object that the variable is pointing to, you will need some way to copy that object.
Either you can implement a copy method on the object itself (if you know what properties it has) or you can iterate through all properties on the object using a for ... in loop and copy them to a newly allocated object.
Something like:
//o is the object you want to copy
var o2 = {}; //gives a new object
for (x in o) {
o2[x] = o[x];
}
Your code:
var myVariable = 1;
function test () {
var myVariableAtSomePoint= myVariable;
console.log(myVariableAtSomePoint);
}
myVariable = 2;
test(); // Prints 2, instead of 1.
You assign 2 to myVariable, and then assign myVariable (which has now value of 2) to myVariableAtSomePoint via test() so of course it is 2. You don't need any magic copying here (since numbers are primitive) just assigment is enough.
You'll just need to copy each property on the object, of course if there are sub-objects they might get passed by reference as well:
function copy(o) { //could be called "clone"
var i, n;
n = {};
for (i in o)
{
if (o.hasOwnProperty(i)) {
n[i] = o[i];
}
}
return n;
}
You can do something this to do exactly what you wanted. It is slightly more involved however.
var myVariable = 1;
var test = null;
(function() {
const myVariableAtSomePoint = myVariable;
test = function() {
console.log(myVariableAtSomePoint);
}
})();
myVariable = 2;
test(); // Prints 1
I thought any variable defined in a function would be local but I can easily access variable 'e' outside of its function.
function change() {
var d = 6;
e = 7;
}
change();
alert(e); //> alerts 7
Because new variables will enter the global scope by default. var prevents this from happening by constraining a variable's existence to be within the current scope.
Because it was declared without var it becomes part of the global window object.
You've not explicitly declared it as such, so it has taken global scope.
Thats because e is global by default, using var make a scope varible.
You can read more about this in Javascript Garden Scope and Namespaces
I am guessing that you are going under this assumption that
JSLint expects that a var will be
declared only once, and that it will
be declared before it is used.
Problem with your code is you are using one var, but your second line has no var in front of it. That is pushing that varaible e into the global namespace.
Why is it happening? You used a semicolon instead of a comma in the variable declaration.
function change() {
var d = 6, //Change this to a comma
e = 7;
}
change();
alert(e); //will produce an error now
It is surprisingly easy to create global variables, here are some other gotchas I've seen.
// :-( antipattern: implied global variable
function sum(x, y) {
result = x + y; // result is global
return result;
}
// :-) better
function sum(x, y) {
var result = x + y; // result is local
return result;
}
// :-( antipattern: chain assignments as part of a var declaration
function foo() {
var a = b = 0; // b is global
}
// :-) better
function foo() {
var a, b;
a = b = 0; // both local
}
I was wondering if there is any way to access variables trapped by closure in a function from outside the function; e.g. if I have:
A = function(b) {
var c = function() {//some code using b};
foo: function() {
//do things with c;
}
}
is there any way to get access to c in an instance of A. Something like:
var a_inst = new A(123);
var my_c = somejavascriptmagic(a_inst);
A simple eval inside the closure scope can still access all the variables:
function Auth(username)
{
var password = "trustno1";
this.getUsername = function() { return username }
this.eval = function(name) { return eval(name) }
}
auth = new Auth("Mulder")
auth.eval("username") // will print "Mulder"
auth.eval("password") // will print "trustno1"
But you cannot directly overwrite a method, which is accessing closure scope (like getUsername()), you need a simple eval-trick also:
auth.eval("this.getUsername = " + function() {
return "Hacked " + username;
}.toSource());
auth.getUsername(); // will print "Hacked Mulder"
Variables within a closure aren't directly accessible from the outside by any means. However, closures within that closure that have the variable in scope can access them, and if you make those closures accessible from the outside, it's almost as good.
Here's an example:
var A = function(b) {
var c = b + 100;
this.access_c = function(value) {
// Function sets c if value is provided, but only returns c if no value
// is provided
if(arguments.length > 0)
c = value;
return c;
};
this.twain = function() {
return 2 * c;
};
};
var a_inst = new A(123);
var my_c = a_inst.access_c();
// my_c now contains 223
var my_2c = a_inst.twain();
// my_2c contains 446
a_inst.access_c(5);
// c in closure is now equal to 5
var newer_2c = a_inst.twain();
// newer_2c contains 10
Hopefully that's slightly useful to you...
Answers above are correct, but they also imply that you'll have to modify the function to see those closed variables.
Redefining the function with the getter methods will do the task.
You can do it dynamically.
See the example below
function alertMe() {
var message = "Hello world";
console.log(message);
}
//adding the getter for 'message'
var newFun = newFun.substring(0, newFun.lastIndexOf("}")) + ";" + "this.getMessage = function () {return message;};" + "}";
//redefining alertMe
eval(newFun);
var b = new alertMe();
now you can access message by calling b.getMesage()
Of course you'll have to deal with multiple calls to alertMe, but its just a simple piece of code proving that you can do it.
The whole point to that pattern is to prevent 'c' from being accessed externally. But you can access foo() as a method, so make it that it will see 'c' in its scope:
A = function(b) {
var c = function() {//some code using b};
this.foo = function() {
return c();
}
}
No, not without a getter function on A which returns c
If you only need access to certain variables and you can change the core code there's one easy answer that won't slowdown your code or reasons you made it a closure in any significant way. You just make a reference in the global scope to it basically.
(function($){
let myClosedOffObj = {
"you can't get me":"haha getting me would be useful but you can't cuz someone designed this wrong"
};
window.myClosedOffObj = myClosedOffObj;
})(jQuery);
myClosedOffObj["you can't get me"] = "Got you now sucker";
Proof of concept: https://jsfiddle.net/05dxjugo/
This will work with functions or "methods" too.
If none of the above is possible in your script, a very hacky solution is to store it in a hidden html-object:
// store inside of closure
html.innerHTML+='<div id="hiddenStore" style="display:none"></div>';
o=document.getElementById("hiddenStore")
o.innerHTML="store this in closure"
and outside you can read it with
document.getElementById("hiddenStore").innerHTML
You should be able to use an if statement and do something like:
if(VaraiableBeingPasses === "somethingUniqe") {
return theValueOfC;
}