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!
Related
I am wondering if this way is correct:
var userInput = confirm('roll die?');
var rollDie = function() {
while(userInput) {
var dieSide = Math.floor(Math.random() * 6);
document.write('you rolled a ' + (dieSide + 1));
userInput = false;
}
}
rollDie(userInput);
Or do I need to write var rollDie = function(userInput) {
Javascript works with scopes. You call the function 'rollDie' from a scope where 'userInput' is a variable. The function 'rollDie' has its own scope. In your example there's no variable 'userInput' in the scope of the function rollDie. There for javascript is looking for the variable in an outer scope and find the variable. So your program is working but the code is not good code.
because you call the function rollDie with the parameter 'userInput' you should add 'userInput' as param to the function rollDie. var rollDie = function(userInput) {} It is always better the give a function all the params the function needs to execute. This prefents problems with the 'this' scope in javascript when you call the function in an other context and make it easier to refactor your code.
twoStrars is quicker :)
You should understand the difference and then choose for yourself.
Basically, you have these two patterns:
x as global variable:
var x = 1;
var f = function() {
console.log('x in f:', x);
x = 2;
}
console.log('x before f:', x);
f();
console.log('x after f:', x);
and x as argument:
var x = 1;
var f = function(x) {
console.log('x in f:', x);
x = 2;
}
console.log('x before f:', x);
f(x);
console.log('x after f:', x);
There two main differences:
if f uses a global variable, it is going to modify the global variable, whereas if it works with an argument, it does not affect any variables visible outside, i.e. the first code writes x after f: 2, whereas the second writes x after f: 1
if f uses a global variable, then it becomes less convenient to pass it different values. With an argument, you don't even need a global variable, you can call f(1); f(2); f(3456);. With global vaiables, you would accomplish the same with var x=1; f(); x=2; f(); x=3456; f();.
Instead of going more into details, I'll give you a link: Why are global variables evil?
Anyway, there are cases when global variables are good! I would make a global variable for a value which is constant and used by multiple functions (var GRAVITY = 9.81; or var BASE_URL = "https://stackoverflow.com/";)
This line:
rollDie(userInput);
…means you're trying to pass a value into your rollDie() method. This isn't strictly necessary because you have this variable declared globally:
var userInput = confirm('roll die?');
So, you could pass nothing in if you wanted, but if you want to write much cleaner code it's preferable to avoid having these global variables around as much as you can. The way you've written it – passing in a value to your function – is much nicer, so it's better to write var rollDie = function(userInput) {.
function emergency() {
var ambulance = 100;
var callAmbulance = function() { alert(ambulance); }
ambulance++;
return callAmbulance;
}
var accident = emergency();
accident(); // alerts 101
I am referring to the variable 'ambulance'.
When I call accident(); it should call emergency() which should use the declared variable 'ambulance' [considering the global scope thing in javascript, still it could set the value to global] but its using old value 101 instead of setting again back to 100 - behaving more like static var.
What's the Explanation?
What you have there is called a closure. It means a function can access variables declared in outer functions (or in the global scope). It retains access even after the 'parent' function has returned. What you need to understand is that you don't get a copy. The changes performed on that variable are visible to your inner function, which in theory means you could have multiple functions sharing access to the same variable.
function f () {
var x = 0;
function a() { x += 1; }
function b() { x += 2; }
function show() { console.log(x); }
return {a:a, b:b, show:show};
}
var funcs = f();
funcs.a();
funcs.b();
funcs.show(); // 3
One thing to be aware of is that a subsequent call to f will create a new scope. This means a new x variable will be created (new a, b, show functions will be created as well).
var newFuncs = f();
newFuncs.a();
newFuncs.show(); // 1
funcs.a();
funcs.show(); // 4
So, how do you get a copy? Create a new scope.
function g () {
var x = 0;
var a;
(function (myLocal) {
a = function () { myLocal += 1; }
}(x));
x += 200;
return a;
}
JS only has pass-by-value so when you call the anonymous function, the xvariable's value will be copied into the myLocal parameter. Since a will always use the myLocal variable, not x, you can be certain that changes performed on the x variable will not affect your a function.
If, by any chance, you're coming from a PHP background you are probably used to do something like
use (&$message)
to allow modifications to be reflected in your function. In JS, this is happening by default.
You are creating a function definition which is not compiled at this time:
var callAmbulance = function() { alert(ambulance); }
And before you are sending it to the called function, you are incrementing the num:
ambulance++;
And then you are sending it to the called function:
return callAmbulance;
But whether you are sending it there or not, it doesn't matter. The below statement executes or compiles the function:
var accident = emergency();
And this takes in the current ambulance value which is 101 after the increment. This is an expected behaviour in creating function but not executing it. Please let me know, if you didn't understand this behaviour. I will explain it more clearly.
I don't understand a part of the accpeted answer of this OP:
Javascript function scoping and hoisting
Writer says:
"
Also, in this instance,
function a() {}
behaved the same as
var a = function () {};
".
What I know is that function expression is different than function declaration, at least for hoisting. Why are they similar in this case?
Why are they similar in this case?
Because var is hoisted (but not set), like a function declaration is hoisted, meaning that there is an a in the local scope before a = 10; is evaluated, so the global a never gets modified - the identifier lookup finds the local a first so sets that
Related parts of the other question
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Why is a === 1?
That the answer was trying to say was that b is equal to
function b() {
function a() {}
a = 10;
return;
}
Similar to
function b() {
var a = function () {};
a = 10;
return;
}
i.e. there is an identifier a defined in b, so
function b() {
var a = 10;
return;
}
And now, obviously, the global a will not be modified by b
Please note that the position of the var isn't really important, just that it's there, the following will produce the same behaviour
function b() {
a = 10;
return;
var a;
}
The difference is that the first line is defined at run-time, whereas second line is defined at parse-time for a script block.
Look at the full answer on stack, here : var functionName = function() {} vs function functionName() {}
I have a little doubt in my mind, that how javascript interpreter works! Specially for the case I am mentioning here.
var a = 5;
function foo(){
debugger
a = 100;
if(false){
var a = 10;
}
a = 1000;
}
foo();
console.log(a);
Simply copy and paste the above code in browser's console, the expected answer is 1000.
What it returns is 5.
I have put debugger knowingly, when it hits debugger, the SCOPE section shows variable a as in scope with undefined. So the further assignment is done to local variable a, that was not meant to be created at all, as it is in false block.
I am aware about the scope of variable is not limited to {}, but it is limited to function. But this case is a surprise!
Can anyone explain this?
var declarations encompass the entire scope.
function() {
a = 5;
var a = 10;
}
is equivalent to:
function() {
var a;
a = 5;
a = 10;
}
So a is a local variable in the scope of the function, not global in the first part and local afterwards (that would be so complicated!).
Little formatting to your code.
var a = 5;
function foo(){
debugger
a = 100;
if(false){
var a = 10;
}
a = 1000;
}
foo();
console.log(a);
Hoisting is the keyword you are looking for. Javascript hoists the variables. Means it puts the declaration of your local variables at top of functions irrespective its going to be executed or not. So after interpretation your code looks like following.
var a = 5;
function foo(){
var a;
debugger
a = 100;
if(false){
a = 10;
}
a = 1000;
}
foo();
console.log(a);
So a becomes a local variable inside function, hence change of value inside function only changes local variable and not global. Hence console prints 5, global variable, value of which was never changed.
It's because you have a var a in the code. All declarations in the function are hoisted to the top, even if it looks like var a = 10; will never execute. Remove var and it will behave as expected.
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
}