Excellent questions: I’ll answer the second first.
- Why does code inside the function know what
a
and b
are?
Because the function was declared inside the same “scope” as a and b were, it has access to anything that was declared in the same scope (the top of the total program), and if it all the code in the editor window were enclosed in a block (denoted by curly braces), it would have access to that variable, too, like:
let c = 10;
{
let a=8, b=6;
(() => {
a = 6;
b = 8;
c = 2;
})();
}
Notice we see curly braces a LOT (around blocks of code we want to repeat in a loop, around blocks of code we want to be able to execute by name - aka functions, in if/else statements). The rule of thumb for block scoping is: “deeper blocks can access higher blocks, but not the other way around.”
- Don’t a and b have to be declared as part of an array?
No. You don’t “declare variables in an array”. An array is a type of value. Think of variables like buckets. You can put all sorts of stuff into buckets: water, sand, rocks, toys… these are the “values” that we “assign” to our variable buckets. In Javascript, any bucket can hold any type of value. There are primitive values undefined
, null
, boolean
, string
and number
, and everything else including arrays are objects. You may want to park that “arrays are objects” in the back of your mind for now, because arrays are a special type of concept in comp sci which deserve their own discussion. An array is like a row of buckets:
Each bucket gets its own numerical index, which shows how far from the beginning it is. Inside each index we can store values which we call elements. In statically-typed languages like C++, the elements must all be the same type (integer numbers in the example above). In Javascript, every array bucket acts like a JS bucket, and so you can have a number at index 0, a string at index 1, and null
at index 3 if you want. The whole array value is what gets assigned to a variable (numbers
for the above array would be a good name). If we want to access individual buckets to get or set their values, we write the name followed by the index in square brackets, so numbers[3]
would get us 17, and numbers[4] = 33
changes the value in element 4 from 22 to 33. We could also say numbers[5] = a;
, and whatever value was stored in a
would be copied into the bucket at index 5.
Notice that the array indices always run from 0 to array.length-1
. There is a very good reason for this. JS is a high-level language, which keeps the details of the machine from you. In languages like C, you have to deal with the actual RAM of the computer, and ask for a whole contiguous block of memory to store the entire unbroken array. You also just know that the array has a certain location for the first element (the pointer to the array - this will be important later), and if you want to access other elements, you move over from there (see picture below for an array of characters - strings of length 1). The memory location of each element is the location of the beginning of the array + index of the element we want.
THIS is why arrays start at 0.
Whew. Take five, smoke 'em if you got 'em. With that understanding of arrays and variables out of the way, there are several ways to make a new array in Javascript, some of which are below.
let arr1 = Array(5);// five empty slots [0 thru 4], not even "undefined" - just empty
let arr2 = [1, null, "Hello, World!", undefined, ["arrays can be values, too"]]; //five slots, all different types.
The latter way is called an “array literal” because you literally describe each element. When you write the code below, you get a new array literal, the only thing you did different from the code above is to have Javascript lookup the value in a
and b
before assigning those values as elements in the array. The values in the array are now copies. I can change them without affecting what’s in a
or b
because primitives get passed by value (a copy is sent) and objects get passed by reference (a copy of the pointer (see paragraph on arrays in C above) is sent.
let arr3 = [b, a]; //just another array literal
The final piece of the puzzle is the whole code:
// WRONG: "let [a, b] = [b, a]." - a and b are already declared
// we don't need to make more room in RAM for them,
// we just need to fill those RAM buckets with new values.
/*CORRECT code below:*/
[a, b] = [b, a];
What’s happening here is that a new array literal [6, 8]
is being created (because those were the values of b
and a
, respectively when it was created. Notice that we have created a THIRD VALUE without giving it a name. Now that the value returned from the right-hand side of the assignment operator, =
, is known, we can assign that value to the variable listed on the left. Because of the very clever ES6 destructuring syntax, instead of assigning it to a variable (like in our arr3
example above), we are breaking the array up into its elements (destructuring it) and assigning it to multiple variables we have listed in the places of the elements we want to assign to each. So, now our namelessArray[0]
element (6, a copy of what b
was at the time the “nameless array” was created) gets assigned to a
, and our namelessArray[1]
element (8, a copy of what a
used to be) gets assigned to b
. So, without naming a third variable, Javascript created a third AND fourth space in RAM, and used those to swap it. But from the code, only two variables were ever declared.
See you next week, class. Homework is on the homepage, your TA has office hours on Wednesday, and your group projects are due on Friday.