The following code in VS2008 gives me a "variable is already defined" warning:
if (someVar) {
var a = 1;
}
else {
var a = 2;
}
The warning is given on the second var a = .... To cure this warning I have done:
var a;
if (someVar) {
a = 1;
}
else {
a = 2;
}
But is this the correct way to do it?
Thanks,
AJ
Yes, that is the correct way to do it. There is no block scope in javascript; there is only function scope and global scope.
you could also give each "block" functional scope using anonymous functions, although it's not very practical in this case:
if (someVar) {
(function () {
var a = 1;
})();
}
else {
(function () {
var a = 2;
})();
}
As a side note, this is also why for (var i = 0; ...) is discouraged in favor of var i; for (i = 0; ...), to avoid 2 consecutive loops in the same function both trying to declare the variable i
It depends on how you're using those variables afterwards.
If they relate to the same object, then it's the correct way.
If they relate to different objects, then I'd rename the variables, as this would prevent maintenance issues in the future.
Either way is perfectly valid and fine (both examples ensure that the variable is declared with the var keyword), but generally it's best practice to declare your vars at the top of the current code block, as in your second example.
Related
Is it bad to duplicate declaring JavaScript variables? For instance, given the below code, is one approach better than the other? If so, please explain why. Thank you
function func1() {
for (var i = 0; i < 100; i++) {
var myVar=123;
}
}
OR
function func2() {
var myVar;
for (var i = 0; i < 100; i++) {
myVar=123;
}
}
Actually, these code samples are equivalent and will probably compile to the same bytecode.
function func1() {
for (var i = 0; i < 100; i++) {
var myVar=123;
}
}
AND
function func2() {
var myVar;
for (var i = 0; i < 100; i++) {
myVar=123;
}
}
This is because of hoisting, and in fact you could also do:
function func3() {
var i, myVar;
for (i = 0; i < 100; i++) {
myVar=123;
}
}
Although you might save time with function func4() { var myVar=123; } ;)
These are functionally identical.
Javascript takes two passes through code. During the first pass variables are set up (amongst other things).
In your first version, during the first pass of the interpreter it will see that you declare a variable myVar and it will hoist the definition of the variable to the top of the scope (which is the function in this case because loops don't have their own scope in javascript).
Thus in javascript's second pass, when the code is executed (interpreted), everything will be identical.
So, in javascript all variables act as if they were declared at the top of the scope, regardless of where, or if, you declare them.
One of the potentially confusing things about javascript is that it has c like syntax and yet has some significant differences from other c-like languages. And this is one of those differences.
It's generally considered better to declare variables at the beginning of a piece of code (or function), than at random places. One exception being the for-loop.
function func2() {
var myVar; // try to declare all variables here
for (var i = 0; i < 100; i++) { // except for the for-loop variable
myVar = 123;
}
}
Why I'd do this: because other languages work this way as well, so it makes it easier to read. For JavaScript specificity it doesn't really matter since scope works weird in JavaScript.
Main argument for this way of writing the function: readability.
Is there something like a best practise when it comes to declaring variables in javascript before assigning a value to them? Sometimes it's necesary for scope reasons, but what if scope doesn't matter?
// Declare first
(function() {
var foo = 'bar',
a = 500,
b = 300,
c;
// Some things get done here with a and b before c can use them...
c = a * b;
// c is now ready to use...
doSomething(c);
}());
// Declare when needed
(function() {
var foo = 'bar',
a = 500,
b = 300;
// Some things get done here with a and b before c can use them...
var c = a * b;
// c is now ready to use...
doSomething(c);
}());
And I'm also wondering what's best practise for something similar with object literals:
// Add property with null assigned to it
var myObj = {
foo: null,
doSomething: function() {
this.foo = 'bar';
}
};
// Property gets added when value is set
var myObj = {
doSomething: function() {
this.foo = 'bar';
}
};
It is mostly a matter of style.
As var declarations are automatically hoisted up to the top of the scope, it makes sense to place them at top of their scope so that you can read the code closer to how the interpreter will execute it.
Declaring variables at the top of their scope is Crockford's recommendation. And it does make sense as it clears up some common misconceptions.
For example:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
Since var has function scope, all iterations (and functions inside of them) refer to the same i. As all three timed functions will execute after the loop ends, the snippet above logs 3 three times.
Now for those with block scoping experience, the above behavior is not very clear. Rewriting the snippet:
var i;
for (i = 0; i < 3; i++) {
// ...
}
Now, i is declared in the global scope, exactly as the previous snippet. However, this one is much more clear on that.
Another misconception:
(function() {
if (true) {
var foo = 1;
} else {
var foo = 1;
}
}());
Again, in block-scoped languages¹ the above is perfectly valid. However, as var declarations are hoisted up to top of the current function scope at parse time, the above is equivalent to:
(function() {
var foo;
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
The variable is declared twice. Most browsers will just ignore the second declaration and the code will "work", but static code analysis tools such as JSHint will yell at you.
You can rewrite it with only one declaration and it is perfectly valid:
(function() {
if (true) {
var foo = 1;
} else {
foo = 1;
}
}());
But OCD-like coders like me will find it rather ugly. So again, declaring at top of the scope:
(function() {
var foo;
if (true) {
foo = 1;
} else {
foo = 1;
}
}());
Looks much more tidier.
Again, it is mostly a matter of style. Personally, if I have a giant function, I hate to scroll all the way up just to check whether a variable is already declared and adding it to the list. In that case, I may just add a couple of var declarations in the middle of the function (against Crockford's recommendation) which I personally find easier to read and maintain.
As it is a matter of style, just make sure to keep your code the most maintainable and concise possible.
In the other side of the coin, I'll admit that, personally, I've started and mostly used var declarations when the variable is firstly used. This is an aspect of the language and you can use it this way without problem.
But I will also admit that, if I had followed Crockford's recommendations from the start, I'd have had many less headaches (as with the misconceptions shown above) and would have grasped JavaScript's function scoping aspect much faster.
¹ Note that JS 1.7 introduced block-scoped variables through let, but it is not widely supported yet.
I am aware that most common practice would be to put var a,b; on the top, but I want to extract every possible character (after running on JS Uglify), and it seems they don't delete unnecessary var initializing
I want to know if any of the following will cause problems and which is recommended
Case 1:
if(condition){
var a=-1;
var b="++";
}else{
var a=1;
var b="--";
}
Case 2:
if(condition){
var a=-1;
var b="++";
}else{
a=1;
b="--";
}
Case 3:
if(condition){
a=-1;
b="++";
}else{
var a=1;
var b="--";
}
This is the way it should be:
var a,b;
if(condition)
{
a = -1;
b = "++";
}
else
{
a = 1;
b = "--"
}
Variables should always be declared at the top of the function with the var keyword. Variable scope is at the function level, and not using var makes it a global variable. Declaring it at the top always ensures that you know the scope is for the entire function (and it is anyway), so when another programmer looks at it and doesn't know that scope is at the function level, he/she wont get confused and think the scope is only in the conditional.
It doesn't matter, since JavaScript has function scope, not lexical scope.
You can think of it as every var ...; statement being shunted up to the top of the function they're in. (That's what I do, at least.)
I'd write the code as
var a, b;
if(condition) {
a = -1;
b = "++";
} else {
a = 1;
b = "--";
}
I'm trying to reuse a complicated function, and it would work perfectly if I could change the value of a local variable that's inside a conditional inside that function.
To boil it down:
var func = complicated_function() {
// lots of code
if (something) {
var localvar = 35;
}
// lots of code
}
I need localvar to be some other number.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Update: The answer is yes! See my response below.
Is there any way to assign localvar to something else, without actually modify anything in the function itself?
Nope.
No, but it is possible to assign it conditionally so that the function signature (basically, the required input and output) does not change. Add a parameter and have it default to its current value:
var func = complicated_function(myLocalVar) {
// lots of code
if (something) {
// if myLocalVar has not been set, use 35.
// if it has been set, use that value
var localvar = (myLocalVar === undefined)?35:myLocalVar;
}
// lots of code
}
No.
Without changing the complicated function there is no way, in javascript you can manipilate this by using call and apply. You can override functions in the complicated function or add new if this is an option (but they won't be able to access the local variable localvar).
this is more for fun my real answer is still no.
If you are feeling crazy :)
var complicatedFunction = function() {
var i = 10;
var internalStuff = function() {
console.log(i); // 10 or 12?
};
return internalStuff();
};
var complicatedFunction;
eval("complicatedFunction = " + complicatedFunction.toString().replace(/i = 10/, 'i = 12'));
complicatedFunction(); //# => 12
If the function uses this.localvar:
var func = function() {
alert(this.localvar)
if (true) {
var localvar = 35;
}
// lots of code
alert(this.localvar)
}
var obj = {localvar: 10};
func.call(obj); // alerts 10 twice
If not, then you can't change it without changing the function.
In javascript variables are "pushed" to the top of their function. Variables in javascript have function scope, not "curly brace" scope like C, C++, Java, and C#.
This is the same code with you (the developer) manually pushing it to the top:
var func = complicated_function() {
var localvar = 0;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
}
Does declaring the variable "up" one function help you out? At least the declaration is isolated.
function whatever() {
var localvar = 0;
var func = function() {
var something = true;
// lots of code
if (something) {
localvar = 35;
}
// lots of code
};
func();
alert(localvar);
}
whatever();
Here is the jsFiddle: http://jsfiddle.net/Gjjqx/
See Crockford:
http://javascript.crockford.com/code.html
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
I asked this question about three weeks ago and within a half hour got five answers that all basically told me it wasn't possible.
But I'm pleased to announce that the answer is YES, it can be done!
Here's how:
var newfunc = func.toString().replace('35', '42');
eval('newfunc = ' + newfunc);
newfunc();
Of course, it uses eval, which probably means that it's evil, or at least very inadvisable, but in this particular case, it works.
Is there any way to change a variable while out of scope? I know in general, you cannot, but I'm wondering if there are any tricks or overrides. For example, is there any way to make the following work:
function blah(){
var a = 1
}
a = 2;
alert(blah());
EDIT (for clarification):
The hypothetical scenario would be modifying a variable that is used in a setInterval function which is also out of scope and in an un-editable previous javascript file. It's a pretty wacky scenario, but it's the one I intend to ask about.
No. No tricks or overrides. You have to plan to have both places be able to see the variable in the same scope.
The only trick I can think of regarding scope is using window in a browser to get to the global object. This can help you get to a "hidden" variable--one that's in scope but whose name has been overtaken by a local variable (or other variable closer in the scope chain).
Closures and classes can afford you some other tricks with scope, but none that allow you to override the scoping rules entirely.
i don't see why you would need to do that, if you need a variable that is accessible from the outside, just declare it on the outside.
now, if you are asking this just because you are trying to learn something, good for you.
var a = 0;
function blah() {
a = 1;
return a;
}
a = 2;
alert(blah());
You can return the value from the function, of course:
function blah() {
var a=1;
return a;
}
But I assume that's not quite what you had in mind. Because a function invocation creates a closure over local variables, it's not generally possible to modify the values once the closure is created.
Objects are somewhat different, because they're reference values.
function blah1(v) {
setInterval(function() {
console.log("blah1 "+v);
}, 500);
}
function blah2(v) {
setInterval(function() {
console.log("blah2 "+v.a);
}, 500);
}
var a = 1;
var b = {a: 1};
blah1(a);
blah2(b);
setInterval(function() {
a++;
}, 2000);
setInterval(function() {
b.a++;
}, 2000);
If you run this in an environment with a console object, you'll see that the value reported in blah2 changes after 2 seconds, but blah1 just goes on using the same value for v.
Functions can access variables declared outside their scope, if they are declared before the function itself:
var a = 0;
function blah() {
a = 1;
}
a = 2;
alert(blah());
Note that your use of var a inside the function declared a local variable named a; here, we omit the keyword as otherwise it would hide a as declared in the outer scope!
No, that will never work, but you could use a global:
var a;
function blah(){
a = 1
}
a = 2;
alert(blah());
or use a closure:
function bleh() {
var a;
function blah(){
a = 1
}
a = 2;
alert(blah());
}
or you could pass it around with a return (which behaves differently, but probably is what you want to do):
function blah(a){
a = 1
return a;
}
a = 2;
alert(blah(a));