Understanding Scope - javascript

I thought I understood scope however, while thinking of a particular code problem I had, I am confused by the following:
var a = {
aFunc: function() {
console.log(x);
}
};
var b = {
bFunc: function() {
var x = c.x;
console.log(x);
a.aFunc();
}
};
var c = {
x: 'x is in c'
};
b.bFunc();
Question: aFunc is called inside bFunc, why do I get 'x is not defined' inside aFunc? Isn't this a simple closure where a.aFunc can access b.bFunc scope?

Isnt this a simple closure where a.aFunc can access b.bFunc scope?
No. Closure is a property of the functions which encloses over all the variables in their scope, during their definition, not during their invocation.
In your case, when a.aFunc is called, it doesn't enclose the variables in b.bFunc because, it is just invoked there, not defined there.
Let's try to understand this, with this example
function Test1(func) {
var a = 0;
func();
}
function Test() {
var a = 5;
Test1(function() {
console.log(a);
});
}
Test();
will print 5, because when func() is executed, the actual function object has enclosed over the variables in Test, since the closure happens during the function definition.

No, every function has it's own scope. A function call doesn't share it's scope with it. If you want to share variables via scope you have to put them in the shared scope like this:
var x = 'x from shared scope';
var a = {
aFunc: function() {
console.log('aFunc: ' + x);
}
};
var b = {
bFunc: function() {
var x = 'x only in scope b';
console.log('bFunc: '+ x);
a.aFunc();
}
};
b.bFunc();

Related

Is it completely impossible to reach into a JavaScript closure? [duplicate]

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;
}

Functions created with the Function constructor are always created in the global scope

From the MDN description of Function:
Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.
I understand,
var y = 10;
var tester;
function test(){
var x = 5;
tester = new Function("a", "b", "alert(y);");
tester(5, 10);
}
test(); // alerts 10
Replacing the tester = new Function("a", "b", "alert(y);"); with tester = new Function("a", "b", "alert(x);");, I will get
// ReferenceError: x is not defined
But couldn't understand the author's line-
...they always are created in the global scope.
I mean how is the new Function("a", "b", "alert(y);"); nested within the test fn is in global scope?
In fact, accessing it from outside the test fn will simply result in
Uncought TypeError:tester is not a function
Please elucidate.
In your example, "created in the global scope" means that tester will not have closure over x from test:
function test(){
var x = 5;
tester = new Function("a", "b", "alert(x);"); // this will not show x
tester(5, 10);
}
When you new up a Function, it does not automatically capture the current scope like declaring one would. If you were to simply declare and return a function, it will have closure:
function test(){
var x = 5;
tester = function (a, b) {
alert(x); // this will show x
};
tester(5, 10);
}
This is the trade-off you make for having dynamically compiled functions. You can have closure if you write the function in ahead of time or you can have a dynamic body but lose closure over the surrounding scope(s).
This caveat doesn't usually matter, but consider the (slightly contrived) case where you build a function body as a string, then pass it to a function constructor to actually be evaluated:
function addOne(x) {
return compile("return " + x + " + 1");
}
function addTwo(x) {
return compile("return " + x + " + 2");
}
function compile(str) {
return new Function(str);
}
Because the function is instantiated by compile, any closure would grab str rather than x. Since compile does not close over any other function, things get a bit weird and the function returned by compile will always hold a closure-reference to str (which could be awful for garbage collection).
Instead, to simplify all of this, the spec just makes a blanket rule that new Function does not have any closure.
You have to create an object to expose via return inside the test() function for it to be global. In other words, add var pub = {} and name your internal functions as properties and/or methods of pub (for example pub.tester = new func) then just before closing test() say return pub. So, that way it will be publically available (as test.tester). It's Called the Revealing Module Pattern.
What it means is that inside the function you can only refer to global variables, as you've found. However, the reference to the function itself is still in the local scope where it was created.
I'm confused as to where the confusion is.
It says that the function will be in global scope...and therefore will only have access to its own scope and the global scope, not variables local to the scope in which it was created.
You tested it and it has access to its own scope and the global scope, not variables local to the scope in which it was created.
So where's the confusion?
Is it in your assigning of the function to the variable testing? testing is just a local variable with a reference to the function...that has nothing to do with the scope of the creation of the function.
Scope is lexical, and has to do with where the function is created, not what random variables a function reference happens to be assigned to at runtime. And the documentation is telling you that when you make a function this way it acts as if it was created in the global scope...so it's acting completely as expected.
Here's an illustration:
This:
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and errors as not defined
tester = new Function("console.log(y); console.log(x);");
}
Is similar to this:
var y = 10;
var tester;
function test()
{
var x = 5;
// also 10 and errors as not defined
tester = something;
}
function something()
{
console.log(y);
console.log(x);
}
NOT
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and 5...since x is local to the function creation
tester = function()
{
console.log(y);
console.log(x);
}
}

Javascript inner function with colon

I know that you can write following
var obj = {
test: 'something'
}
But in this code, the inner function does not refer to a variable, but to a function.
Is there any other way to write / call the inner function?
function outer(){
var a = "Outerfunction";
console.log(a)
innerFct: function InnerFct() {
var c = "Inner";
console.log(c)
} innerFct();
}
window.outer();
There are a couple of different things going on here.
In this code:
var obj = {
test: 'something'
}
you are using "literal object notation" to create -- well, an object with one property test and that property has a value of something
In your second case, you are creating a code block (yes, it is fun that both objects and code blocks use the same syntax {...} to define them.
Inside of a code block, the innerFct: becomes a label. Labels are used with some control flow statements to jump around. Forget about them, you really are better off not using them.
function outer(){
var a = "Outerfunction";
console.log(a)
function innerFct() {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
or even
function outer(){
var a = "Outerfunction";
console.log(a)
var innerFct = function () {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
You are confusing functions with objects.
When using an object, the colon is used to show key-value pairs.
var object = {
innerFct: function(){
console.log('rawr');
},
someVariable: 7
}
object.innerFct(); //logs rawr
object.someVariable = 4; //just changed from 7 to 4
Using a colon how you have it in your example is incorrect syntax. Also when you are creating a function within an object like that, you don't name the function again because you are already assigning it to a name on the object.
Then you can edit the function anytime by doing something like this:
object.innerFct = function(){
//new code
}
Doing object.innerFct() will call the function.
Other answers have sufficiently covered the object syntax and calling the function in scope. As I mentioned in the comment, you can just do this:
function outer(){
(function () {
var c = "inner";
console.log(c)
})();
}
window.outer();
And it logs inner just fine.
Edit: Private/hidden variables like innerFct in the original code sample can be captured in closures as well.
outer = function() {
var innerFct = function () { console.log("inner"); }
// innerFct is captured in the closure of the following functions
// so it is defined within the scope of those functions, when they are called
// even though it isn't defined before or after they complete
window.wrapper = function() { innerFct(); }
return function() { innerFct(); }
}
outer();
// each of these next three lines logs "inner"
window.wrapper(); // assigned to global variable
outer()(); // calling the returned function
var innerFctBackFromTheDead = outer(); // saving the returned function
innerFctBackFromTheDead();
There is also the object constructor/prototype syntax.
function Outer() {
this.inner = function() {
this.c = "inner";
console.log(this.c);
}
}
var out = new Outer();
out.c; // undefined
out.inner(); // logs "inner"
out.c; // "inner"
More information on the new keyword and prototypes: http://pivotallabs.com/javascript-constructors-prototypes-and-the-new-keyword/

Is there a way to access a shadowed variable in JavaScript?

var a=1; //first one
function x() {
var a=2; // second
function y() {
var a=3; // third one
}
}
Is there any way that function y() can access the second var a? I know it can access first one via window.a.
As-written?
No.
If you're not dead-set on naming each one a, then you can easily reference it.
The other solution would be to capture the outside variable within another variable, the trick being to not have the same variable name being referenced in the outside scope, from the inside scope.
window.a = 1;
function x() {
var a = 2,
inner_a = a,
y = function () {
var old_a = inner_a,
// a is equal to the closest var assignment ie: inside x()
a = 3;
};
}
or to pass it into the construction of a new function through closure
(immediately-invoking function)
window.a = 1;
function x() {
var a = 2;
var y = (function (old_a) {
return function () { var a = 3; };
// this inner function has access to "old_a", through closure
}(a));
}
This is a pattern that is preferred for several use-cases, when mixing JS with browser-functionality (ie: the DOM and DOM events, loops which assign timers or callbacks, AJAX responses, et cetera).

Self invoking function is undefined

If I declare a function literal:
var x = function(){
alert('hi');
};
console.log(x); // returns the function code.
However:
var x = (function(){
alert('hi');
})();
console.log(x); // returns undefined?
I don't understand why this happens. Isn't the point of writing a function as a literal is to still be able to access it by its variable reference name? I know this may be silly but I'm just learning javascript so don't judge too harshly.
Your function does not return anything, so its return value is undefined.
A self-executing function is executed and the function is not stored anywhere - only its return value survives (and any external variables the function sets/modifies).
For example, this code would be equivalent to var x = 'hi';:
var x = (function(){
return 'hi';
})();
The purpose of self-invoking functions is usually to create a new scope, e.g. when creating callback functions in a loop:
for(var i = 0; i < 5; i++) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
}
This would use the same i in all callbacks so it would alert i = 5 5 times.
for(var i = 0; i < 5; i++) {
(function(i) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
})(i);
}
By using a self-executing function we create a new scope and thus a new i in each loop.
Another use of self-executing functions is to create a new scope where certain variables are ensured to be available and set to the correct value:
(function($, window, undefined) {
// here the following always applies:
// $ === jQuery
// window === the global object [assuming the function was executed in the global scope]
// undefined is well, undefined - in some js engines someone could have redefined it
})(jQuery, this);
If you:
var foo = somefunction;
… then you assign a function to foo.
If you:
var foo = somefunction();
… then you assign the return value of a function call to foo
Your function:
function(){
alert('hi');
}
… has no return statement, so it will return undefined.

Categories

Resources