Functions and variable scope: local and global variables
Variable scope is the part of a program where a variable can be used. A variable declared inside a function is local: it exists only while that function runs, and only that function can see it. A variable declared outside every function is global, and any part of the program can read and change it.
The examples below are in JavaScript, and you can paste any of them into the Code Editor and run it. The ideas are the same in Python, pseudocode and most other languages.
What is a function?
A function is a named block of code that does one job. You write it once and call it by name whenever you need that job done, which keeps programs shorter and easier to test. Exam boards call functions and procedures subroutines: the AQA GCSE specification describes a subroutine as a named "out of line" block of code that can be called.
function area(width, height) {
return width * height;
}
console.log(area(4, 7)); // 28Parameters and arguments
width and height are parameters: names in the definition that stand for the inputs. The values in the call, 4 and 7, are arguments. They are matched to the parameters in order, so width becomes 4 and height becomes 7.
Return values, functions and procedures
return ends the function and sends a value back to the line that called it, so area(4, 7) is replaced by 28. In GCSE terms, a subroutine that returns a value is a function, and one that just does something, such as printing, without returning a value is a procedure. JavaScript and Python use the word function for both.
Try it: put the lines of this function in order so it returns the target text, then press Mark to check your answer in the course.
Drag code snippets into the function to produce the target output.
Press Mark to have your answer marked in the HTML, CSS & JavaScript course.
What is variable scope?
Scope answers one question: from this line, which variables can I see? MDN defines it as the context in which values and expressions are visible. There are three levels to know.
| Scope | Declared | Can be used | Exists until |
|---|---|---|---|
| Global | Outside every function | Anywhere in the program | The program ends |
| Local (function) | Inside a function, including its parameters | Only inside that function | The function returns |
| Block | With let or const inside { }, such as a loop or if | Only inside those braces | The block finishes |
Local and global variables
let total = 0; // global
function addScore(points) {
let bonus = 5; // local
total = total + points + bonus;
return total;
}
console.log(addScore(10)); // 15
console.log(addScore(3)); // 23
console.log(bonus); // ReferenceError: bonus is not definedtotal is global, so addScore can change it and the change is still there on the next call. bonus and the parameter points are local. They are created fresh on every call and thrown away when the function returns, which is why the last line fails.
Shadowing: the same name inside and outside
If a function declares a local variable with the same name as a global one, the local one wins inside the function. This is called shadowing. The global variable is untouched.
let count = 1;
function reset() {
let count = 99; // a new local count
return count;
}
console.log(reset(), count); // 99 1Block scope: let, const and var
In JavaScript, let and const are block scoped: a variable declared inside a loop or an if statement disappears at the closing brace. The older var ignores blocks and is scoped to the whole function, or made global if it is outside any function. That is one reason modern code avoids var.
for (var i = 0; i < 3; i++) {}
console.log(i); // 3: var leaks out of the loop
for (let j = 0; j < 3; j++) {}
console.log(j); // ReferenceError: j is not definedNested functions
A function written inside another function can see its own variables, the outer function's variables and the globals. It looks outwards, one level at a time, until it finds the name. It can never look inwards.
let a = "global";
function outer() {
let b = "outer";
function inner() {
let c = "inner";
return a + " " + b + " " + c;
}
return inner();
}
console.log(outer()); // global outer innerHere inner can use a, b and c. outer can use a and b but not c, and code outside both can use only a.
Code Editor
Write and run code right in your browser
The call stack
The call stack is how the computer keeps track of which function is running. Each call pushes a stack frame holding that call's parameters, local variables and the place to return to. When the function returns, its frame is popped off and its local variables go with it. The last function called is the first to finish, so the stack is last in, first out (LIFO).
When outer() runs above, the stack grows like this:
- The main program calls
outer: its frame, holding b, goes on the stack. outercallsinner: a frame holding c goes on top.innerreturns its text: its frame is popped and c is gone.outerreturns: its frame is popped and b is gone. Only the global a is left.
Recursion and the base case
A recursive function calls itself on a smaller version of the problem. It needs a base case, a condition where it stops calling itself, or the calls never end.
function sumTo(n) {
if (n === 1) return 1; // base case
return n + sumTo(n - 1); // recursive case
}
console.log(sumTo(4)); // 10sumTo(4) needs sumTo(3), which needs sumTo(2), which needs sumTo(1). That is four frames on the stack at once. The base case returns 1, then each frame adds its own n on the way back: 1 + 2 + 3 + 4 = 10. Without the base case the stack fills up and the program crashes, which JavaScript in Chrome reports as "RangeError: Maximum call stack size exceeded".
Higher-order functions and callbacks
In JavaScript a function is a value, like a number or a string, so you can pass it into another function. A function that takes or returns a function is a higher-order function, and a function passed in is a callback.
const addThree = (n) => n + 3;
function twice(f, x) {
return f(f(x));
}
console.log(twice(addThree, 10)); // 16twice calls the callback on 10 to get 13, then on 13 to get 16. Array methods such as map and filter, and event handlers on web pages, all work this way. The Programming Languages course covers the functional style this leads to, and how the stack and heap manage memory.
Common mistakes
- Using a local variable outside its function. It no longer exists once the function returns. Return the value instead.
- Mixing up parameters and arguments. Parameters are the names in the definition; arguments are the values in the call.
- Forgetting to return. A function with no
returngives backundefinedin JavaScript andNonein Python. - Changing globals from inside functions. It works, but any function could be the one that changed it, so bugs are hard to find. Pass values in as parameters and return results.
- Recursion with no base case, or a recursive call that never gets closer to it.
Common questions
What is scope in programming?
What is the difference between a local and a global variable?
Why should you avoid global variables?
What is the difference between a function and a procedure?
Is var function scoped in JavaScript?
What is a stack overflow?
Revision cards
Say the answer first, then flip the card to check it.
Where to go next
- Solve it
Code Editor
Write and run code right in your browser
Open the tool - Learn it
HTML, CSS & JavaScript
Learn how to think like a web developer from the ground up
Start the course - Test it
GCSE Computer Science
A new exam-style paper every day, with instant marking and a mark scheme
Start today's paper