Can somebody please explain me why the following code works?
function getLastName()
{
fullName.lastName = "World";
}
function writeName()
{
fullName = {};
fullName.firstName = "Hello";
getLastName();
document.write(fullName.firstName + " " + fullName.lastName);
}
writeName();
For some reason, getLastName() can reach local its enclosing method's local state. How can this work? And also should I utilize this feature of Javascript or it is considered as a bad practice? If it is a bad practice, could you please explain why?
You can see the actual code working here at http://jsbin.com/atituk/2/edit
You don't have any local variables, that would require using the var keyword. All your variables are global and can be accessed anywhere within window, which is not considered good practice at all.
You have not used the var keyword against fullName inside the writeName function, you are therefore taking it from the scope outside writeName. It continues up the chain until it reaches the outer most scope, at which point it creates a global.
Globals are, in general, bad practise as they are hard to keep track of and more likely to be overwritten by accident (e.g. in a race condition).
If you were using strict mode this would create an error instead of a global.
You are using all variables of yours as global variables. So all are recognized everywhere. In order to have a better understanding of variable scopes in Javascript have a look at this great example https://stackoverflow.com/a/500459/655316
Related
I am just learning JavaScript, and I don't understand why the following code doesn't produce an error:
myTest = 5;
function addFifteen(num) {
return num+15;
}
document.write(addFifteen(myTest));
Why do I not need "var" before "myTest"? If it runs without "var", what is the purpose of writing that?
When you do not specify a var before the variable, it is still valid javascript. This is why it does not produce an error. However, as a best practice, you should avoid this, because variables thus declared get tagged to the global scope window.
Having too many variables / functions thus declared is said to "pollute" your global scope and isn't considered good programming practice.
There is a more thorough explanation about this on MDN
var variableOne;
var variableTwo;
var variableThree;
function veryInterestingFunction() {
var variableFour;
if(a){
variableFour = 'Good';
}
else {
variableFour = 'Decent';
}
console.log(variableFour);
}
$(window).on('scroll', function(){
veryInterestingFunction();
});
Here I have some variables in the global scope, a function declaring a variable and assigning a value to it, and calling this function on scroll.
This way on every scroll you are going to declare the "variableFour" which is not a good practice, right?
However I don't want to crowd the global scope with unnecessary variables and also can't use an IIFE. Is there a "best practice" way to declare the variable outside the function and still only possible to use it inside the scope of that function ?
http://jsfiddle.net/2jyddwwx/1/
to declare the variable outside the function and still only possible to use it inside the scope of that function ?
I guess, that's impossible
When I don't want to crowd the global scope, I will declare one global object, for example App = {}, and instead of global variables, I use it's properties.
App.variableOne;
App.variableTwo;
App.variableThree;
Or you can use classes in ES6
I don't think there's anything wrong with your code sample, I seriously doubt variable declaration is ever going to slow down your code. I'd definitely only start to worry about this kind of thing when you're absolutely certain it's causing issues (it won't), otherwise it might be wasted effort.
If you really want to optimize this, one thing you might be able to do is debouncing the veryInterestingFunction calls - that is if you don't necessarily need to respond to every single scroll event (depends on your logic).
As per your question, IIFE/function closure is essentially the only way to limit scope in JavaScript that I know of, so if you can't use that, I don't see any other option.
There is no problem in declaring an empty variable into your scope. If it is not global, it belongs to the scope.
And there is no need to fear for performance. If you declare variables within your scope, the Javascript garbage collector will empty that for you. Take a read at this article
"[JavaScript functions] internally store any variables they may refer to that are defined in their enclosing scopes."
How can I determine what that set of variables is?
For example, David Herman in Effective JavaScript gives this function (and closure):
function sandwichMaker() {
var magicIngredient = "peanut butter";
function make(filling) {
return magicIngredient + " and " + filling;
}
return make;
}
var f = sandwichMaker();
document.writeln("<p>" + f("jelly") + "</p>");
document.writeln("<p>" + f("bananas") + "</p>");
document.writeln("<p>" + f("marshmallows") + "</p>");
Sure, magicIngredient is a variable accessible to make(), but what else is? What if sandwichMaker were itself within a function? And then there are the globals. What is the function looking at when it looks for relevant values within the current scope?
What if sandwichMaker were itself within a function? And then there are the globals.
Yes, all the variables from parent functions are accessible (if they are not shadowed). And the highest-scoped function inherits from the global scope then.
What is the function looking at when it looks for relevant values within the current scope?
You can inspect that with a debugger. Insert a debugger; statement in make, and then execute it and have a look into your devtools. You will see something like this:
Scope Chain
0. make (currently executed):
this: (+)Window
arguments: (+)Arguments
filling "jelly"
1. sandwichMaker:
arguments: (+)Arguments
magicIngredient: "peanut butter"
make: (+)Function
Global
AnonXMLHttpRequest: …
ApplicationCache: …
Array: …
…
Also have a look at this great article: http://dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/
Example view at Chrome Devtools:
(from www.briangrinstead.com):
JavaScript uses function scope. This is pretty simple to understand - anything declared in a function has scope to that function as well as any higher scopes.
A closure can be thought of as two things being combined together: a particular scope, and a particular point in time (when the function was created).
Sure, magicIngredient is a variable accessible to make(), but what
else is?
Anything that was accessible to the scope of make at the time it was created. This includes all variables in the make function as well as any higher scopes. The scope of make is said to be closed-over the scope that existed at the point in time it was created, always giving it access to magicIngredient.
What if sandwichMaker were itself within a function?
Then make would have access to that scope (as it existed at the time make was created) as well.
And then there are the globals. What is the function looking at when it looks
for relevant values within the current scope?
The interpreter will search the currently executing scope for any referenced variables. If it can't find them, it will look in the next higher scope. It will continue looking higher and higher until it finds the variable or runs out of scopes (the global scope is the highest, aka the window object for javascript running in a browser).
A related concept is shadowing - two variables can have the same name in parent/child scopes, the child is said to "shadow" the parent because it will take precedence. Note this is a bad practice.
The easiest way to understand how closures and scoping works is to understand a simple factory pattern, such as this one. When the inner function is created and returned, it is bound to that scope at that point in time and will continue to alert the proper values even after the values no longer exist.
Hope this helped - lots of questions stuffed into one question :)
Suppose above function sandwichMaker() there was a variable defined...
var something = 'something';
function sandwichMaker () {
...
You can access something from within sandwichMaker() AND from within make().
The outer variables are accessible from within the functions. If you were to set var something = 'something else' within make(), then you would be effectively hiding the outer var something while within the make() function itself. However, you can just set something = 'something else', and the value will have changed at all scopes. It only hides the value if you declare that variable again.
I've got a problem of having code variable names conflicting each other, ie;
<script type="text/javascript">var a = "hello"; </script>
<script type="text/javascript">alert(a);//this works, when I want 'a' not to exist </script>
Are closures the only option?
Coming from a c# background, its like constructing an unreferenced instance of a delegate, then calling it inline, which seems a bit messy
(function(){var a = "hello";})();
(function(){alert(a);})();//yes! working as expected
Using a (immediately self-executing) function to create a new scope is indeed the way to go.
This also has the advantage that you can ensure that certain variables have certain values. When using jQuery, the following is common for example:
(function($, window, undefined) {
// ...
})(jQuery, this);
Unless you have tons of functions with only a single statement in each (like in your example) it is also perfectly readable.
Yes, closures are your only option. In browsers all JavaScript files get put into the same global scope.
IIFE's are very common place in JavaScript; I wouldnt' call them messy.
Javascript only has function scope, unlike C# which has block scope. The following code is valid javascript and C#:
var x = 2;
while(true) {
var y = 3;
break;
}
//y is not accessible here in C#, but is in javascript
The only way to create a new scope is to create and execute an anonymous function.
For short, inline stuff then you're best to use the module pattern to create a closure and therefore emulate private variables.
(function(){
var a....
})();
A better long-term approach is to use objects as namespaces.
var NS = {};
NS.a = 1;
Just to provide a different perspective. It is possible to write code without using closures, and maintain (arguably) safe global variable scope.
Define a single object, to use as a namespace, with a suitably unique name (e.g. MyAppContext) that will have global scope, and if you need to define global-like variables only for use in your application only, attach them to this object.
MyAppContext.appTitle = 'Application Title';
At the start of your script where you create MyAppContect make sure it doesn't aleady exist.
Make sure that all of your function-scoped variables use the var keyword so you know you're not referencing a global value.
Obviously this approach opens up a risk that you forget to define some of your function variables with var. JSLint can help you in respoect of this this.
I am happy to retract this answer if I start getting flamed, but I believe it is a workable alternative approach to using closures. And hey! it's old skool
I also agree that the use of closures is safer, but thought this might interest you.
A local function in the closure declares a variable with the same name which exists in the closure. So, how could we access closure's variable from the local function?
function closure()
{
var xVar;
function func1()
{
var xVar;
// how to distinguish local and closure scopes.
return xVar;
}
return function () { return func1(); };
}
Creating a private object and making private variables as properties of this object could help. But I am wondering if there is a better and neat solution. Can a scope chain help?
I have edited to make it a complete closure. Anyway, closures are not much concern here, it could be considered for inner functions however, there may be a solution with closures somehow.
Thanks
You can't access the scope chain explicitly in JS. Your problem is the age-old one of variable shadowing, but it's that much more maddening because in JS, the scope chain is actually there at runtime, it's just not available for you to access.
You can play some tricks with rejiggering current scope if you use the hated with operator, but that (as well as arguments's caller/callee stuff) really just give you access to objects and functions with their properties. There's no way to say "give me what xVar means in the n-1 runtime scope from right here".
Variables defined in an inner scope hide variable declarations in an outer scope. The "better and neat solution" is not to reuse variable names that way.
In your example the xVar variable is not a closure, because you redefined its scope to each function. To use that variable as a closure continue to declare it with the var command in the closure() function and then do not declare it with the var function in the func1() function. Instead just use the variable immediately in func1().
There is not an easy way to test if a function is a closure or a local variable. You would have to perform some sort of flow control test and then analyze assignments, where assignments occur, and where assignments do not occur. Then you must compare those results. You could write a tool, in JavaScript, to perform that analysis upon a given input and write you a report as output.