Lifetime of Variables
In the programming you learned, you could declare variables in several ways.
At first we defined variables in the draw
block.
When you used iteration, you defined variables in the control statement of a for loop, and when you started using functions, you defined them in the argument section.
Actually, there is a concept of lifetime, which is called scope, as the extent to which a variable can be used as a valid one, and it depends on where it is declared.
The goal of this chapter is to organize the scope of variables, which has not been clearly explained in previous chapters, and to be able to use them appropriately.
In fact, the scope of javascript has been refined over the years and is now a fairly complex rule. Here, we will focus on how to write them so you are less likely to make mistakes.
Local Variables
In general, a variable declared with the let keyword is valid within its block. You have used blocks as a way to organize processing when using for loops, if statements, and functions. Variables declared within such a block are called local variables and expire as soon as the program execution proceeds and exits the block. The variable cannot be used after exiting the block.
Check how the scope works in the program that only outputs text to the console. Also, remove any inaccessible variables and eliminate errors that occur in each program.
[Check how the function scope works.]
function function1(arg) {
// declare a local variable with the function scope for function1
let scope = 'local';
// accessible within the scope of function1
print(scope); // -> local
print(arg); // -> argument
}
function setup(){
function1('argument');
// cannot access local variables or arguments from outside the function scope.
print(scope); // -> ReferenceError
print(arg); // -> ReferenceError
}
[Check how the block scope works]
function setup(){
// i is valid only in the for block
for(let i=0; i<10; i++){
print(i);
}
print(i);
// j is valid only in the if block
if(true){
let j = 10;
print(j);
}
print(j);
}
It is nice to have a variable scope that allows you to create variables with the same name in different blocks without conflict.
In the following example, the variables x, y
are declared as arguments of function1, in function2, and in draw function* respectively, but all three are treated as separate variables with the same name.
function function1(x, y){
// When you use x, y in this block, it refers to those in parentheses
...
}
function function2(){
let x = 10;
let y = 20;
// When you use x, y in this block, it refers to the above variables
...
}
function draw(){
let x = 0;
let y = 100;
// When you use x, y in this block, it refers to the above variables
function1(x, y); // pass x=0. y=100 to function1
function2(); // variables in function2 does not affect to this scope
}
What would be the problem if there was no concept of scope and the variables declared could be used anywhere in the program? Programmers must always keep track of what variables are declared throughout the program and create names for them without any overlap. This may be possible with a small program of a few dozen lines, but when the program becomes large and uses many variables, it is no longer possible for a human brain to manage this. This is also a source of mistakes, such as rewriting variables that are not expected. To avoid mistakes, declare variables in smaller blocks to minimize the influence of outside variables.
The following two are also important rules regarding the scope of variables.
- In nested blocks, the same variable can be used in lower level blocks.
- In the event of a variable name conflict in a nested block, the scope of the smaller variable is valid.
In the following program, the block of setup
and the block of for loop have a hierarchical structure.
Variables declared in the setup
block are valid in the for block.
However, i
is declared again for the for statement, so it has a smaller scope and takes precedence.
function setup(){
let i = 1000;
let j = 2000;
// i = 1000, j = 2000
print("(i, j) in setup block is (" + i + ", " + j + ")"); // ★
for(let i=0; i<10; i++){
// i is declared again. i = 1, i = 2, ...
// j is still j = 2000
print("(i, j) in for loop is (" + i + ", " + j + ")");
}
// out of for loop, it refers the first i. i = 1000, j = 2000
print("(i, j) after loop is (" + i + ", " + j + ")");
}
Strings are also a type of variable and can be edited. The operator
+
can be used to concatenate strings, for example"open" + "processing"
is"openprocessing"
.If you put a number in the operator, it will be converted to a string and concatenated, so the above code will output
(i, j)
as(1000, 2000)
in the console.
Global Variables
Even though the scope of variables should be as small as possible, you may still have situations where you want to use common variables from many functions. In such cases, we have no choice but to use global variables. Global variables are declared outside of function blocks, and their scope spans the entire program.
[Example 6-1. global variable]
let a = 80; // define a global variable a outside of a function
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
stroke(255);
noLoop(); // do not animate
}
function draw() {
// refer to the global 'a' to draw a line
line(a, 0, a, height);
a += 10; // updated the global variable 'a'. a = 90 here.
drawAnotherLine();
drawYetAnotherLine();
}
function drawAnotherLine() {
// define a local a to draw a line
let a = 320;
line(a, 0, a, height);
}
function drawYetAnotherLine() {
// As there is no 'a' in this block, the global 'a' is referred.
a += 10; // updated the global 'a'. a = 100 here.
line(a, 0, a, height);
}
When a global variable and a local variable are declared with the same name, the local variable takes precedence according to the rule of smaller scope wins. Although there are some situations in which it is convenient to use global variables, they should be used only as a last resort because, as already mentioned, they are a source of mistakes, such as rewriting variables that were not intended.
Also, global variables are treated as a single variable throughout the animation. In the following program example 6-2, you can see how the line increases as the global variable a is incremented by +10 (press replay). In p5.js, global variables are often used to have information that changes during the animation.
let a = 80; // define a global variable 'a'
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
stroke(255);
}
function draw() {
// draw a line using the global 'a'
line(a, 0, a, height);
a += 10; // the global 'a' is rewritten.
}
Declare Constants
Sometimes you want to store a constant, such as pi, that has a fixed value and will never be rewritten.
In javascript, you can create a value that cannot be changed by declaring it using const
.
A constant declared in this way will raise an error if you try to rewrite the it.
Other than rewriting, the scope and other rules are the same as for variables declared with let
.
A constant can also be declared as a function argument, and the argument cannot be rewritten within that function.
This has not been introduced in the main chapters, but should be used proactively because it prevents mistakes due to unintentional rewriting.