Trying to figure out how scope works - javascript

I'm trying to learn JS on codeacademy and I can't understand/get past this thing. Can someone please provide an answer and also an explanation of why is it so? Would deeply appreciate.
// This function tries to set foo to be the
// value specified.
function setFoo(val) {
// foo is declared in a function. It is not
// accessible outside of the function.
var foo = val;
}
setFoo(10);
// Now that we are outside the function, foo is
// not defined and the program will crash! Fix this
// by moving the declaration of foo outside of the
// function. Make sure that setFoo will still update
// the value of foo.
alert(foo);

You can see scope as a term meaning what variables you can reach at a specific "level" in the code. In JavaScript, these "levels" are defined by functions. Each function introduces a new level.
For example, take this sample code:
var a;
// you can access a at this level
function function1() {
var b;
// you can access a, b at this level
function function2() {
var c;
// you can access a, b, c at this level
}
}
So in your case, you should declare var foo; outside the function, preferably above it. Then you can set it inside setFoo with foo = val;. foo then refers to the one you declared in the level above setFoo.
foo is accessible both in setFoo and in the alert call that way; compare it with the above sample code (function1 is setFoo, a is foo and the alert call is in the top-most level. function2, b and c are not used in your case.).

// Create globale variable
// (You should not use globale variables!)
var foo;
// set value
function setFoo(val) {
foo = val;
}
setFoo(10);
// show value
alert(foo);

Just declare foo outside any function then it will be global:
var foo = null;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo);
Try it !

When you declare a variable in Javascript it is only visible to code that is in the same function as it is declared, or a function inernal to that function. Because foo is originally declared in the SetFoo function nothing outside of SetFoo is able to see it, so the call to alert fails as foo does not exist in the gloabl scope.
As the comments suggest, moving the declaration of foo out of the function and into the global scope (which you can think of as a catch-all function that contains everything) would allow you to use foo when calling alert.
var foo;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo); // No longer crashes

Every function in Javascript has it's own scope. That means that every variable you define there with the var keyword, will only be available within that function. That means that when you call setFoo(10), you create the variable foo, give it a value of five, after which it is immediately destroyed because it went out of scope.
There are multiple ways to solve this problem. The first would be to remove the var keyword. This would put foo in the global scope, which means that it's available everywhere. However, this is discouraged, you want to keep the global scope as uncluttered as possible, so that if you have javascript code provided by multiple people on the same page, they can't overwrite other people's variables. Another way to do it would be this:
function setFoo(val){
var foo = val;
alertfoo = function(){
alert(foo)
}
}
In this example, the only thing you're putting in the global scope is the alertfoo function, because you want that to be available everywhere. The alertfoo function is defined inside the setFoo function, this means that although foo should have gone out of scope after setfoo has been executed, it is kept in memory, because alertfoo has access to it.
This makes for some nice tricks. For example, let's say you're making a javascript library that will be included on other people's pages, you'll want to create a scope inside of which you can define variables, without polluting the global scope. The most common way to do this, is by declairing a self-executing function. This is a function which is executed immediately after being defined, it looks like this:
(function(){
//set variables you want to be global in your own code
var mainpage = document.getElementById('main');
//define functions you want to make available to other people in a way that puts them in the global scope
setMainElement = function(newmain){mainpage = newmain;}
})();
You can make this even better by making only one object global, and provide your interfae through the methods of that object, this way, you create a namespace with all the functions that your library contains. The next example uses an object literal to do this. In javascript, you can create an object by putting key/value pairs petween curly braces. the key/value pairs are properties of the object. for example:
(function(){
var privatevar = 10,otherprivate=20;
publicInterface = {
'addToPrivate': function(x){privatevar+=x;},
'getPrivate': function(){return private}
};
})();

Original code:
function setFoo(val) {
var foo = val;
}
setFoo(10);
alert(foo); // Crash!
Their advice to fix the crash:
Fix this by moving the declaration of foo outside of the function
I'm guessing you're confused as to what they mean by "outside of the function".
Try this edited code:
var foo = 5; // "var" declares the variable to be in this outer scope
function setFoo(val) {
foo = val; // but we can still access it in this inner scope...
}
setFoo(10);
alert(foo); // Displays a dialog box that says "10"

Variables defined in the function is valid only in the function
function setFoo(val) {
foo = val;
}

In JavaScript, new scopes are only created by functions

Related

Does a function's name act as a variable?

I have a question about this code below:
function myfunc () {
return 2 + 2;
}
console.log(myfunc);
Does anyone know why, when we log 'myfunc' to the console, we get the entire function itself back? Or in other words, is 'myfunc' acting as a variable that holds the function's contents, or is it just referencing that function?
Because if I go ahead & add this to the code...
myfunc = undefined; //or any other value like myfunc = 20;
...then since myfunc's value is changed, I can no longer use it to invoke the function. So what is 'myfunc' really?
The answer is yes, a function declaration creates a symbol in the local function scope (or global scope if the declaration is in that context) that works exactly like a variable declared with var (though function declarations are hoisted above var declarations).
Now, a function expression like this:
var x = function helloWorld() { return "hello world"; };
does not create a local "helloWorld" symbol (except when it does). The value of a function expression is a reference to the created function, and that can be assigned to a variable just like any other value.

Is there any difference if I wrap a function inside another?

What is the difference between these two?
I import both in browserify and they seem to give the same result.
Is there any difference between them and how they work?
var App = (function () {
var Foo = function (name) {
this.name = name;
};
Foo.prototype.logout = function () {
console.log();
}
return Foo;
})();
module.exports = App;
VS
var Foo = function (name) {
this.name = name;
};
Foo.prototype.logout = function () {
console.log();
}
module.exports = Foo;
In this particular case, the only difference is that in the first code sample you end up with a variable named "App", and in the second you end up with one named "Foo". Other than that effect on the namespace, the two do the same thing.
More generally, code that looks like this:
var x = function() {
// lots of stuff
return something;
}();
allows for "lots of stuff" to be done in a context that's isolated from the surrounding context. That means that functions and variables defined inside that anonymous function won't "leak out" into the surrounding context unless that's an explicit goal of the return statement (or other code that otherwise affects some outer context somehow, most typically by direct modifications to window or something like the jQuery prototype).
In your example, again, the "lots of stuff" in the second example didn't involve altering any namespace other than that function prototype, which the first code does too.
Yes, there is difference between these two. First example keeps you safe from polluting your global scope with Foo variable, since it's wrapped in IFEE(Immediately Invoked Function Expressions) and assigned to variable App. Since Foo is inside IFEE it belongs to IFEE's scope.
Foo variable from second example is in global scope and if you import this file in some other code Foo would override variable from that file if there also exist variable with that name. So to be sure that this wouldn't happen it's better to wrap imported code into IFEE.
Also, accessing variable Foo is different, in first example you would access it with App.Foo (since it's namespaced under App) and in second you access it with Foo.

Reusable Javascript function

I'm building reusable function, but I can't change global variables values.
var foo = 5;
function MyFunction(arg) {
setInterval(function(){
foo = 2 + arg;
return foo;
}) ;
}
foo = MyFunction(1);
alert( foo );
After function complete I'm getting undefined;
Thanks in advance.
var foo = 5;
function MyFunction(arg) {
foo = 2 + arg;
}
MyFunction(1);
alert( foo );
You assigned the result of MyFunction invocation to foo and that's why you got undefined. MyFunction has no return statement.
ekuusela gives the right answer as to why your (presumably simplified) example doesn't work.
There are lots of reasons why you could have problems with globals, the most common being that you are accidentally clobbering a global by using the same identifier in some other function, and forgetting to declare it locally. To this day I still get problems where I've written for (i=0;i<n;i++) without first declaring var i in that function-- which then uses a global i, and works fine until 6 months later I make the same mistake somewhere else...
As a useful tip for debugging, the expression var G = (function(){return this})() will always give you the global object, no matter where you run it, including eval'd code. You can then access the global variable foo as G.foo, evaluate ('foo' in G) to check whether such a global exists, and so on.
In order to define a global variable you can use variable name without var keyword or define the variable outside any function scope. Then you can access it by the given method :
foo = 5;
function MyFunction(arg) {
window.foo = 2 + arg;
}
MyFunction(1);
alert( window.foo );
Note: Now foo is a part of window object.

A better understanding of javascript precompile

var foo=1;
function bar(){
foo=10;
return;
function foo(){}
}
bar();
alert(foo);
I am currently learning on how javascript is actually running in the machine and this is a piece of code I see in the example. I got no idea why the final alert is 1 instead of 10. So I am wondering could any one help me explain how the javascript virtual machine is actually execute these code. Thanks!
This is due to function declaration hoisting:
var foo=1;
function bar(){
function foo(){} // This gets moved up here by the engine
foo=10; // You've reassigned the local `foo` function to 10,
// leaving the global `foo` untouched
return;
}
bar();
alert(foo); // Since the foo has never changed in this scope, it's still 1
I got no idea why the final alert is 1 instead of 10.
Because the foo in this line in bar:
foo = 10;
...is the variable-like thing* declared by the function declaration later on in that function:
function foo(){}
...not the foo that's outside bar. That is:
var foo=1;
function bar(){
foo=10; // <== This `foo`
return;
function foo(){} // <== Is the `foo` declared here
}
bar();
alert(foo);
...not to the foo declared in the containing scope (var foo).
There are two reasons that's happening:
Function declarations are processed immediately on entry to the containing scope (the call to bar, in this case), prior to any step-by-step code in the function. This is sometimes called "hoisting" the declarations (because they happen as though they were at the very top). And since the function declaration isn't step-by-step code, the return has no effect on whether it gets processed; it gets processed before the return ever happens.
Function declarations also create what might as well be variables with the names of the functions. So the foo in the function declaration effectively becomes a variable with that name (more below) — and as you've seen in that code, you can assign new values to those "variables."
When you run that code, here's the order of things that the JavaScript engine does:
Creates a variable called foo and gives it the initial value undefined.
Creates the function bar, adding bar as an in-scope symbol (effectively a variable) in the current scope and making it a reference to the bar function.
Starts step-by-step code for that scope.
Assigns the value 1 to foo.
Calls the bar functon.
Creates the foo function relevant to that call to bar, adding foo as an in-scope symbol (effectively a variable) during the call and making it a reference to the function.
Starts the step-by-step code for that scope.
Assigns the value 10 to the local foo (which used to refer to the function).
Returns out of the function.
Calls alert with the foo in that scope, which still has the value 1.
You can read up on all the gory details in §10.4.3 of the spec and the sections it links to.
* "variable-like thing" In JavaScript, each execution context (the global context and any contexts created by calling functions, etc.) has an object that it uses to hold various names used in that context and their values; it's called a "binding object." The binding object for a context (I'm skipping some unrelated details here) has properties for each variable, function declaration, and a few other things like the arguments pseudo-array, the name of the function itself (referring back to the function), and such. The name of the properties are the names of the variables, declared functions, etc. That's why assigning to foo inside bar overwrites the reference to the foo function declared in bar, instead of assigning to the variable in the outer scope. foo is effectively a local variable in bar, even though it's not declared with var, because of the function declaration.
This has to do with a concept called hoisting. function foo is essentially just an alternative syntax for var foo = function .., so inside bar the name foo does not refer to the outer foo variable but to a locally defined foo. This foo is first a function, but later gets overwritten by 10.
Now, through hoisting the name foo is "reserved" and scoped at parse time, before the code executes. Essentially, it executes like this:
function bar(){
var foo = function () {};
foo = 10;
return;
}
Hence it does not overwrite the outer variable at all.

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)

Categories

Resources