Declare variables at top of function or in separate scopes?
Variables should be declared as locally as possible.
Declaring variables "at the top of the function" is always a disastrously bad practice. Even in C89/90 language, where variables can only be declared at the beginning of the block, it is better to declare them as locally as possible, i.e. at the beginning of smallest local block that covers the desired lifetime of the variable. Sometimes it might even make sense to introduce a "redundant" local block with the only purpose of "localizing" the variable declaration.
In C++ and C99, where it is possible to declare variable anywhere in the code, the answer is pretty straightforward: again, declare each variable as locally as possible, and as close as possible to the point where you use it the very first time. The primary rationale for that is that in most cases this will allow you to supply a meaningful initializer to the variable at the point of declaration (instead of declaring it without initializer or with a dummy initializer).
As for the memory usage, in general a typical implementation will immediately (as you enter the function) allocate the maximum space required for all variables that exist at the same time. However, your declaration habits might affect the exact size of that space. For example, in this code
void foo() {
int a, b, c;
if (...) {
}
if (...) {
}
}
all three variables exist at the same time and generally the space for all three has to be allocated. But in this code
void foo() {
int a;
if (...) {
int b;
}
if (...) {
int c;
}
}
only two variables exist at any given moment, meaning that space for only two variables will be allocated by a typical implementation (b
and c
will share the same space). This is another reason to declare variables as locally as possible.
The benefits of declaring variables at the top of the function body in JavaScript
Declaring variables at the top helps you avoid situations like this:
function outer() {
var i = 50;
function inner() {
alert(i);
var i= 30;
}
inner();
}
outer();
Many people would expect the alert to show 50
, and they would be surprised to see undefined
. That's because the i
variable is declared within the inner
function, but it isn't initialized until after the alert
. So it has full function scope, even though it's declared after its initial use.
Variable declaration placement in C
It compiles successfully because GCC allows the declaration of s
as a GNU extension, even though it's not part of the C89 or ANSI standard. If you want to adhere strictly to those standards, you must pass the -pedantic
flag.
The declaration of c
at the start of a { }
block is part of the C89 standard; the block doesn't have to be a function.
Where you can and cannot declare new variables in C?
I also often hear that putting variables at the top of the function is the best way to do things, but I strongly disagree. I prefer to confine variables to the smallest scope possible so they have less chance to be misused and so I have less stuff filling up my mental space in each line on the program.
While all versions of C allow lexical block scope, where you can declare the variables depends of the version of the C standard that you are targeting:
C99 onwards or C++
Modern C compilers such as gcc and clang support the C99 and C11 standards, which allow you to declare a variable anywhere a statement could go. The variable's scope starts from the point of the declaration to the end of the block (next closing brace).
if( x < 10 ){
printf("%d", 17); // z is not in scope in this line
int z = 42;
printf("%d", z); // z is in scope in this line
}
You can also declare variables inside for loop initializers. The variable will only exist only inside the loop.
for(int i=0; i<10; i++){
printf("%d", i);
}
ANSI C (C90)
If you are targeting the older ANSI C standard, then you are limited to declaring variables immediately after an opening brace1.
This doesn't mean you have to declare all your variables at the top of your functions though. In C you can put a brace-delimited block anywhere a statement could go (not just after things like if
or for
) and you can use this to introduce new variable scopes. The following is the ANSI C version of the previous C99 examples:
if( x < 10 ){
printf("%d", 17); // z is not in scope in this line
{
int z = 42;
printf("%d", z); // z is in scope in this line
}
}
{int i; for(i=0; i<10; i++){
printf("%d", i);
}}
1 Note that if you are using gcc you need to pass the --pedantic
flag to make it actually enforce the C90 standard and complain that the variables are declared in the wrong place. If you just use -std=c90
it makes gcc accept a superset of C90 which also allows the more flexible C99 variable declarations.
Declaring variables at top of js file
Declaring variables at the top of the function they should be scoped to (which is the top of the file for globals), is a common practice used to:
- Avoid confusion new developers experience when encountering hoisting
- Make it clear which variables are scoped where to developers reading the code (but putting them all in one place per scope).
It doesn't introduce any problems (beyond altering the way you have to clean up old code when you stop using a variable).
What is the scope of variables in JavaScript?
TLDR
JavaScript has lexical (also called static) scoping and closures. This means you can tell the scope of an identifier by looking at the source code.
The four scopes are:
- Global - visible by everything
- Function - visible within a function (and its sub-functions and blocks)
- Block - visible within a block (and its sub-blocks)
- Module - visible within a module
Outside of the special cases of global and module scope, variables are declared using var
(function scope), let
(block scope), and const
(block scope). Most other forms of identifier declaration have block scope in strict mode.
Overview
Scope is the region of the codebase over which an identifier is valid.
A lexical environment is a mapping between identifier names and the values associated with them.
Scope is formed of a linked nesting of lexical environments, with each level in the nesting corresponding to a lexical environment of an ancestor execution context.
These linked lexical environments form a scope "chain". Identifier resolution is the process of searching along this chain for a matching identifier.
Identifier resolution only occurs in one direction: outwards. In this way, outer lexical environments cannot "see" into inner lexical environments.
There are three pertinent factors in deciding the scope of an identifier in JavaScript:
- How an identifier was declared
- Where an identifier was declared
- Whether you are in strict mode or non-strict mode
Some of the ways identifiers can be declared:
var
,let
andconst
- Function parameters
- Catch block parameter
- Function declarations
- Named function expressions
- Implicitly defined properties on the global object (i.e., missing out
var
in non-strict mode) import
statementseval
Some of the locations identifiers can be declared:
- Global context
- Function body
- Ordinary block
- The top of a control structure (e.g., loop, if, while, etc.)
- Control structure body
- Modules
Declaration Styles
var
Identifiers declared using var
have function scope, apart from when they are declared directly in the global context, in which case they are added as properties on the global object and have global scope. There are separate rules for their use in eval
functions.
let and const
Identifiers declared using let
and const
have block scope, apart from when they are declared directly in the global context, in which case they have global scope.
Note: let
, const
and var
are all hoisted. This means that their logical position of definition is the top of their enclosing scope (block or function). However, variables declared using let
and const
cannot be read or assigned to until control has passed the point of declaration in the source code. The interim period is known as the temporal dead zone.
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
Places where can I declare variables in JavaScript
Variables can be declared at top-level, function parameter lists, and statements in function bodies.
Object and array literals can contain nested functions, and you can declare variables inside these functions as well. But you can't declare variables directly in object/array literals; e.g. you can't write:
const foo_array = [
let a = 1,
let b = 2
];
Related Topics
Casting Pointer to Array (Int* to Int[2])
Are There Any MACros to Determine If My Code Is Being Compiled to Windows
Do I Need to Close a Std::Fstream
C++/Win32: How to Wait for a Pending Delete to Complete
Conflict Between Dynamic Linking Priority in Osx
How to Building Static Qt with Static Openssl
Defining a Variable in the Condition Part of an If-Statement
Is There Support in C++/Stl for Sorting Objects by Attribute
How to Create Unique_Ptr That Holds an Allocated Array
Do Child Threads Exit When the Parent Thread Terminates
Variable Number of Parameters in Function in C++
What Happens When I Mix Signed and Unsigned Types
How to Prevent Stack Allocation of an Object and Only Allow It to Be Instantiated with 'New'
Why Was 1 << 31 Changed to Be Implementation-Defined in C++14
C++ Template Functions Overload Resolution
Variadic Deduction Guide Not Taken by G++, Taken by Clang++ - Who Is Correct