Week 01
JavaScript, The Basics
Case-sensitive Language
Every identifier in JavaScript is case-sensitive, meaning that a variable with the name Foo is different from a variable with the name foo:
let foo = "foo";
console.log(foo); // "foo"
console.log(Foo); // "Uncaught ReferenceError: Foo is not defined"
Comments
You can use // for single-line comments and /* */ for multi-line comments. Comments are not executed and only used for clarifications:
// this has no effect on the execution
/*
This is a multi-line
comment. Again, no effect on the execution
*/
Ending Statements
Although not necessary, it's a good idea to always end your statements with a ;:
let university = "ucalgary";
Dynamiclly Typed
JavaScript is not statically typed, meaning that the true type of a variable is decided in run-time and can change during the execution of the code:
let name = "Alice";
console.log(name); // "Alice"
name = 5; // this is fine
console.log(name); // 5
console.log(name + 10); // 15
Declaring Variables
The const Keyword
A constant is a "variable" that--unlike variables (declared with the let or var keywords)--cannot be overwritten. Once declared, you cannot change its value:
var college = "bow valley";
const university = "ucalgary";
college = "sait"; // allowed
university = "ubc"; // results in "Uncaught TypeError: Assignment to constant variable." error
The let Keyword
The let keyword declares a variable just like the var keyword does; except that the let keyword blocks off the scope of a variable in any {} blocks, such as for and if/else.
var university = "ubc";
if (university == "ubc") {
var university = "ucalgary";
console.log(university); // ucalgary
}
console.log(university); // ucalgary
var university = "ubc";
if (university == "ubc") {
let university = "ucalgary";
console.log(university); // ucalgary
}
console.log(university); // ubc
Template Strings
Template strings give us a better way to interpolate variables into strings by wrapping them inside ${}:
// old way
console.log(lastName + ", " + firstName + " " + middleName);
// new way
console.log(`${lastName}, ${firstName} ${middleName}`);
They also respect whitespace, making it easy to draw up HTML code.
document.body.innerHTML = `
<section>
<header>
<h1>The UCalgary Blog</h1>
</header>
<article>
<h2>${article.title}</h2>
${article.body}
</article>
<footer>
<p>copyright | The UCalgary Blog</p>
</footer>
</section>
`;
Functions
There are multiple ways to create a function in JavaScript. We'll touch on different methods here.
Function Declarations
Function declarations start with the function keyword, folowed by the name of the function, the parameters it receives, an the body wrapped in curly braces {}.
function greetings(name) {
return `Greetings, ${name}!`;
}
Once declared, you can call it using the function name and the necessary arguments:
console.log(greetings("Alice")); // Greetings, Alice!
Function Expressions
A function expression is just a function declaration assigned to a variable. As functions are first-class citizens in JavaScript, you can assign them to a variable, or even pass them around like a normal variable:
const greetings = function(name) {
return `Greetings, ${name}!`;
}
console.log(greetings("Alice")); // Greetings, Alice!
One difference between function expressions and declarations is that you can't invoke a function before writing a function expression, but you can do so with function declarations:
console.log(greetings("Alice")); // Error: "Uncaught ReferenceError: Cannot access 'greetings' before initialization"
const greetings = function(name) {
return `Greetings, ${name}!`;
}
console.log(greetings("Alice")); // Greetings, Alice!
function greetings(name) {
return `Greetings, ${name}!`;
}
Default Parameters
You can specify a default value for function parameters, just as you would in a language like Python:
const greetings = function(name="Unknown Person") {
return `Greetings, ${name}!`;
}
console.log(greetings()); // Greetings, Unknown Person!
Arrow Functions
Arrow functions are a relatively new addition to JavaScript. You can declare functions without using the functions keyword, and sometimes, without having to use the word return:
const greetings = name => `Greetings, ${name}!`;
console.log(greetings("Alice")); // Greetings, Alice!
If the function takes more than one argument, you need to use ():
const greetings = (name, lastName) => `Greetings, ${name} ${lastName}!`;
console.log(greetings("Alice", "Smith")); // Greetings, Alice Smith!
In case you want to return more than one statement, you need to wrap the function in {} and use the return keyword:
const greetings = (name, lastName) => {
if (name === "Alice") {
return `Greetings, ${name} ${lastName}! How was the Wonderland?`;
}
return `Greetings, ${name} ${lastName}!`;
}
console.log(greetings("Alice", "Smith")); // Greetings, Alice Smith! How was the Wonderland?
Objects and Arrays
Objects and Arrays are variables that can contain many values instead of just one. Objects are a container for key/value pairs. In order to access a field inside an object, we use their key:
const myObject = {
name: "Alice",
occupation: "Student"
};
console.log(myObject.name); // Alice
console.log(myObject.occupation); // Student
Arrays are containers for a list of values. In JavaScript, the values don't have to be of the same type. To access an element inside an array, we use the array index, starting from 0:
const frontendTech = ["JavaScript", "HTML", "CSS"];
console.log(frontendTech[1]); // HTML
console.log(frontendTech.length); // 3. length of the array
Destructuring Objects
Destructuring objects allows us to retrieve only the values we're interested in, instead of the whole object:
person = {
name: "Alice",
occupation: "Student"
};
const { name } = person;
console.log(name); // Alice
person = {
name: "Alice",
occupation: "Student",
age: 25,
goesTo: "University of Calgary",
likes: "Programming"
};
const { name, goesTo, likes } = person;
console.log(`${name} goes to ${goesTo} and likes ${likes}.`); // Alice goes to University of Calgary and likes Programming.
We can use destructuring in function parameters too:
person = {
name: "Alice",
occupation: "Student",
age: 25,
goesTo: "University of Calgary",
likes: "Programming"
};
const printProfile = ({ name, goesTo, likes }) => `${name} goes to ${goesTo} and likes ${likes}.`;
console.log(printProfile(person)); // Alice goes to University of Calgary and likes Programming.
It also works for nested types:
person = {
name: "Alice",
occupation: "Student",
age: 25,
goesTo: {
universityName: "UCalgary",
universityProvince: "Alberta"
},
likes: "Programming"
};
const printProfile = ({ name, goesTo: {universityName, universityProvince}, likes }) => `${name} goes to ${universityName} in the province of ${universityProvince} and likes ${likes}.`;
console.log(printProfile(person)); // Alice goes to UCalgary in the province of Alberta and likes Programming.
Destructuring Arrays
We can also destructure arrays based on their index:
const frontendTech = ["JavaScript", "HTML", "CSS"];
const [firstTech] = frontendTech;
console.log(firstTech); // JavaScript
// note how we ignore the first two using ','
const [,,lastTech] = frontendTech;
console.log(lastTech); // CSS
Adding Items to Arrays
We can use the push() method to append (add) new items to the end of an array:
const fruits = ["apple", "orange"]
fruits.push("banana")
console.log(fruits) // ['apple', 'orange', 'banana']
Object Enhancements
This is the opposite of destructuring. Basicaly, we structure or create new objects this way:
const name = "Alice";
const occupation = "Student";
const enhanced = { name, occupation };
console.log(enhanced.name, enhanced.occupation); // Alice, Student
console.log(enhanced);
We can also attach functions to an object:
const name = "Alice";
const occupation = "Student";
const printProfile = function () {
return `Name is ${this.name} and occupation is ${this.occupation}`;
};
const enhanced = { name, occupation, printProfile };
console.log(enhanced.printProfile()); // Name is Alice and occupation is Studentf
Note the use of this in the printProfile function. this refers to the object that called the function; in this case: enhanced.
The Spread Operator
The spread operator (...) allows us to break down (spread) contents of an array or object.
const frontendTech = ["JavaScript", "HTML", "CSS"];
console.log(...frontendTech); // "JavaScript", "HTML", "CSS"
Let's copy the frontendTech array to a new one using the spread operator:
const frontendTech = ["JavaScript", "HTML", "CSS"];
const copy = [...frontendTech];
copy[0] = "TypeScript";
const [first] = frontendTech;
const [copyFirst] = copy;
console.log(first); // "JavaScript"
console.log(copyFirst); // "TypeScript"
const shallowCopy = frontendTech;
shallowCopy[0] = "TypeScript";
console.log(frontendTech[0], shallowCopy[0]); // "TypeScript", "TypeScript"
The above example shows how we can deep copy an array using the spread operator and change it later without impacting the main array. Otherwise (as shown in the second part of the example), we'll be doing a shallow copy (reference copy) and every change to either arrays will impact the other one as well.
Let's add a new element to an array:
const arr = ["Python", "Golang", "Java"];
const arr2 = [...arr, "JavaScript"];
console.log(arr.length, arr2.length); // 3, 4
console.log(arr); // ["Python", "Golang", "Java"]
console.log(arr2); // ["Python", "Golang", "Java", "JavaScript"]
The spread operator also works with objects:
const person = {
name: "Alice",
occupation: "Student",
age: 25,
goesTo: {
universityName: "UCalgary",
universityProvince: "Alberta"
},
likes: "Programming",
printLikes () { return `${this.name} likes ${this.likes}` }
};
console.log(person.printLikes()); // "Alice likes Programming"
const updatedPerson = {
...person,
// keep everything as is, but replace the "likes" field
likes: "Hiking"
};
console.log(updatedPerson.printLikes()); // "Alice likes hiking"