Javascript - How deeply can a variable retain its value? - javascript

Noob question here. Please see code below.
Where can I read more on this? I mean, this_variable gets 100. All subsequently defined functions seem to be able to access this variable and get it's value, but I wonder how deep does this work? I'm working on a Chrome extension and the damn thing only works with callbacks; I need to be able to access stuff within a pretty deeply nested callback and I need to be sure that what I write is reliable and will remain consistent.
(function(){
this_variable = 100;
(function(){
(function(){
(function(){
(function(){
(function(){
tadaaa = this_variable;
console.log(tadaaa); // sais 100
}());
}());
}());
}());
}());
}());

There is no limit. Though if you're nested deeply enough to worry about a limit, I would question the overall design.

As deeply as you want. The name for the concept is closures and it is the most important concept when programming advanced javascript.

As long as a variable is 'in scope' it can be accessed (presuming it's not hidden). You can nest as much as you like. See here for scoping and closure reference from MDN.

As far as you goes..
It might be slower at some point, but should still be accessible all the way through your callbacks.

Javascript uses function scoping. The rule is if a variable is set within the top level function, then all of the nested functions within the top level function have access to that variable. If a variable is declared within a nested function, then the top level function(s) will not have access to that variable.
//Immediately invoked function that scopes jQuery and outside code cannot access
$(function() {
//top-level function
function test() {
var a = true;
//nested function
function nestedTesting() {
//The nested function has access to a
console.log(a);
var b = false;
}
nestedTesting();
//The top level function does not have access to b
console.log(b);
}
test();
});
Expected Result:
true
Uncaught ReferenceError: b is not defined

Related

Checking if an attribute gets attached to $scope

This question really consists of two:
1 - Do functions create their own $scopes in javasript?
e.g.$scope.foo = function() {
$scope.bar = "Bar";
}
I ask this because in one such test that I'm trying to run I check to determine the existence of a variable on the scope, run a function and then recheck:
iit('getPatientFirstName should attach patientName to the scope', function() {
// Passes
expect(scope.patientName).toBeUndefined();
spyOn(scope,'getPatientFirstName').andCallThrough();
scope.getPatientFirstName(detailsBody);
// Fails
expect(scope.patientName)not.toBeUndefined();
});
// In the controller
$scope.getPatientFirstName = function (dataBody) {
$scope.patientName = dataBody.patientFirstName;
};
So this suggests that they may have their own scope? If this is the case can we test this?
2 - Is a valid alternative just to use an object that exists outside the function:
$scope.patientDetails = {
patientName: ''
};
$scope.getPatientFirstName = function (dataBody) {
$scope.patientDetails.patientName = dataBody.patientFirstName;
};
Thanks
EDIT
Considering the two answers has raised another question - is a variable (attribute or object) considered global if its attached to the $scope? It can be accessed in any function in that controller but as far as being called in a completely different controller - yes it can?
Confirm/Deny anyone?
And it appears that assigning the variable to the $scope global is considered valid for the purposes of my test.
Regarding your first questions, no, functions do not create new $scopes by their own (note that we are talking about scopes and not closures, which are two different concepts).
In your example, the $scope.foo function creates a new bar property on the same $scope object where foo is defined. The final $scope object would look something like this:
$scope {
foo: function() {
$scope.bar = "Bar";
},
bar: "Bar"
}
The problem with your test may be related to the missing . before the not.
expect(scope.patientName).not.toBeUndefined();
Is a valid alternative just to use an object that exists outside the
function:
Yes, you can use an object that's defined outside the function.
If the object is on the same $scope object you will have no problems, just make sure it is defined before you run the function, otherwise you will get a $scope.patientDetails is not defined error.
I'll answer the question a little differently than where you are taking it. I hope it helps you to rethink your stategy.
1 - Do functions create their own $scopes in javasript?
They do create an own scope. But the surrounding scope is also available within the scope. So when you write a function within a function, the inner function can use all the variables of the outer function
Example
function foo() {
var a=5;
function bar() {
var b=4;
}
function hello() {
var c=3;
}
}
a is available for all the functions, foo, bar and hello.
b is not available for foo nor for hello.
c is not available for foo nor for bar.
2 - Is a valid alternative just to use an object that exists outside the function:
So, you should try to make an outer function; there you can declare variables that will be strictly contained within that outer function.
Any function you create within this outer function can make use of that outer scope.
Variables that are global should be avoided if possible.
An example: jQuery.
jQuery has 1 variable that is global: var jQuery ( You can also access it by its alias $ ).
The variables that jQuery uses will not be in conflict with any variables you use.
And anything you want from jQuery, you will have to go through $ (or jQuery)

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 )))

How can I call a function within a closure within a variable?

I'm a newbie in java but the code is below the explanation
This is code from a game but the problem is: Take the navigator function, I click the navigator in the game and some sort of (ajax?) goes on and it gets logged. But when I use my FireBug console I cannot send a message with the functions above the return line.
Essentially.. The only functions that ThisFunction.* shows is the ones returned at the bottom. How can I invoke the Navigator function? I've tried:
ThisFunction.a.navigator(args here);
, but it says a is undefined.. it doesn't show in the autocomplete list either.
** I removed the code because it is from a game. Thanks for the help! **
You somewhat nailed it on its head with this bit:
The only functions that ThisFunction.* shows is the ones returned at the bottom
That is the expected and purposeful functioning of the language.
Short answer: You have to return out of the closure anything that you want to be externally accessible... That could be the a variable, or it could be an api that could itself access the a variable while keeping it private from the exterior. This is called lexical scoping and it is your friend.
Example time:
var ThisFunction = (function() {
var a = { navigator: "woot" };
var b = function() {
return a;
}
});
ThisFunction.a; //a is null/undefined on the returned
ThisFunction.b; //b is defined yay
var aOUTSIDE = ThisFunction.b();
aOUTSIDE.navigator; // "woot"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
So the only things that can get at A are the things that were var'd up in the same "scope" as a. So either you return A out of the scope or you return something from inside the scope that provides an API to either get at A, or to execute some of A's internals...
Depending on what OTHERFUNCTIONSHERE is, you can access it from within one of those functions, if they close over the variable a (why such cryptic var names by the way?). Otherwise, it's out of scope.
Given that you're using Firebug, ThisFunction.%a.navigator(... args) should work (.% is a Firebug-specific extension to the language). But as noted in other answers, it's impossible from pure JavaScript.

Javascript function change variables scope

I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Below is demonstrating what I'm talking about.
I just need to get rid of eval.
//Used to determine where the variable is being stored
var variableScope = "global";
(function(window){
var variableScope = 'insideFunction',
appearingToBeGlobalFunction = function(){
alert("This Function appears Global but really isn't");
};
window["addFunction"]=function(funName,fun){
//window[funName] = fun; Doesn't work
eval("window[funName]="+fun+";");
}
})(window);
addFunction("alertTest",function(){
alert(variableScope);
appearingToBeGlobalFunction();
});
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();
Edit: The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();​
You can't get rid of eval and still expect it to work. That's the only way to take a look at members of the scope after it's been "closed." I've messed around with something similar in the past, but I would never actually use it anywhere. Consider an alternate solution to whatever you're trying to accomplish.
eval("window[funName]="+fun+";");
Oh dear Lord.
The reason this “works” is that you are converting the function fun (alertTest) into a string to put it in the eval argument.
It happens that in most desktop browsers, a native JS function's toString() result will be a string that looks like a function expression containing the same code as the original declaration. You're turning a function back into a string and re-parsing that string in the context of the new enclosing function, so the new function value is the same code but with a different closure.
However, it is not required that Function#toString work like this, and in some cases it won't. It is not safe to rely on function decomposition; avoid.
You can certainly only do this kind of horrific hackery using eval, although there is no reason the window[funName]= part has to be inside the eval. window[funName]= eval('('+fun+')'); would work equally well (badly).
I am attempting to declare a function outside of anonymous function but still have acess to all of the anonymous functions variables
Whyever would you do something crazy like that?
you could force the variables to be in the global scope eg instead of var variableScope = 'insideFunction' you use window.variableScope = 'insideFunction'
The goal of this question was to ultimately keep the global scope clean from tons of variables, but still have the convenience of accessing, set and calling as if they were global. I have concluded there is a way to doing what I'm after but it requires a deprecated functionality in javascript.
Here is some example code showing how to accomplish the above without eval.
This article discusses how to use "with".
var variableScope = "global";
var customScope = {
variableScope : 'insideFunction',
appearingToBeGlobalFunction : function(){
alert("This Function appears Global but really isn't");
}
};
function alertTest(){
with(customScope){
alert(variableScope);
appearingToBeGlobalFunction();
}
};
//should alert "insideFunction" and "This Function appears Global but really isn't"
alertTest();​

How do you explain this structure in JavaScript?

(function()
{
//codehere
}
)();
What is special about this kind of syntax?
What does ()(); imply?
The creates an anonymous function, closure and all, and the final () tells it to execute itself.
It is basically the same as:
function name (){...}
name();
So basically there is nothing special about this code, it just a 'shortcut' to creating a method and invoking it without having to name it.
This also implies that the function is a one off, or an internal function on an object, and is most useful when you need to the features of a closure.
It's an anonymous function being called.
The purpose of that is to create a new scope from which local variables don't bleed out. For example:
var test = 1;
(function() {
var test = 2;
})();
test == 1 // true
One important note about this syntax is that you should get into the habit of terminating statements with a semi-colon, if you don't already. This is because Javascript allows line feeds between a function name and its parentheses when you call it.
The snippet below will cause an error:
var aVariable = 1
var myVariable = aVariable
(function() {/*...*/})()
Here's what it's actually doing:
var aVariable = 1;
var myVariable = aVariable(function() {/*...*/})
myVariable();
Another way of creating a new block scope is to use the following syntax:
new function() {/*...*/}
The difference is that the former technique does not affect where the keyword "this" points to, whereas the second does.
Javascript 1.8 also has a let statement that accomplishes the same thing, but needless to say, it's not supported by most browsers.
That is a self executing anonymous function. The () at the end is actually calling the function.
A good book (I have read) that explains some usages of these types of syntax in Javascript is Object Oriented Javascript.
This usage is basically equivalent of a inner block in C. It prevents the variables defined inside the block to be visible outside. So it is a handy way of constructing a one off classes with private objects. Just don't forget return this; if you use it to build an object.
var Myobject=(function(){
var privatevalue=0;
function privatefunction()
{
}
this.publicvalue=1;
this.publicfunction=function()
{
privatevalue=1; //no worries about the execution context
}
return this;})(); //I tend to forget returning the instance
//if I don't write like this
See also Douglas Crockford's excellent "JavaScript: The Good Parts," available from O'Reilly, here:
http://oreilly.com/catalog/9780596517748/
... and on video at the YUIblog, here:
http://yuiblog.com/blog/2007/06/08/video-crockford-goodstuff/
The stuff in the first set of brackets evaluates to a function. The second set of brackets then execute this function. So if you have something that want to run automagically onload, this how you'd cause it to load and execute.
John Resig explains self-executing anonymous functions here.

Categories

Resources