JavaScript Course 1: Basics

From WikiMLT

Ref­er­ences

Vari­ables and Con­stants

var variableName = '';      // Before ECMAScript 6
let variableName = '';      // After ECMAScript 6
const constName = 'ABC';    // After ECMAScript 6

Nam­ing con­ven­tions, rules:

  • Names can­not be a re­served key­word;
  • They should be mean­ing­ful;
  • Can­not start with a num­ber;
  • Can­not con­tain space or hy­phen.;
  • The names are case sen­si­tive;
  • Use camel­No­ta­tions;

De­fine mul­ti­ple vari­ables or con­stants:

let firstName, lastName;
let firstName = 'Spas', lastName = 'Spasov';
// Best practice is to declare each variable separately:
let firstName = 'Spas';
let lastName = 'Spasov';

Scope (sum­ma­ry from all parts of the course)

Read this sec­tion once again when fin­ish the course. JavaScript vari­ables can be­long to the lo­cal or glob­al scope. Glob­al vari­ables live un­til the page is dis­card­ed, like when you nav­i­gate to an­oth­er page or close the win­dow. Lo­cal vari­ables have short lives. They are cre­at­ed when the func­tion (or oth­er type of code block) is in­voked, and delet­ed when the func­tion is fin­ished.

Vari­ables cre­at­ed with­out a de­c­la­ra­tion key­word (var, let, or con­st) are al­ways glob­al, even if they are cre­at­ed in­side a func­tion (or oth­er type of code block).

A lo­cal scope is de­fined by the JavaScript el­e­ments that us­es code block – {}, like as:

  • Func­tions: func­tion() {…}
  • Loops: while() {…}, for() {…}, etc.
  • Ob­jects: con­st obj = {…}
  • If blocks: if (…) {…}
  • etc.
{
    const message = 'hi';
}
console.log(message);
Uncaught ReferenceError: message is not defined at <anonymous>:1:13

Glob­al vari­ables can be made lo­cal (pri­vate) with clo­sures.

It is bet­ter prac­tice, when it is pos­si­ble, to do not use Glob­al vari­ables.

When we have Lo­cal and Glob­al vari­ables (or con­stants) with ex­act same names – the Lo­cal vari­ables (or con­stants) take prece­dence over the glob­al vari­ables (or con­stants).

Var vs Let and Con­st (is­sues with Var)

Read this sec­tion once again when fin­ish the course.

Is­sue 1

The first is­sue with var is that, it cre­ates func­tion scope, while let (and con­st) cre­ates block scope. So the vari­ables cre­at­ed by var can be ac­cessed out­side of the scope where they are de­fined.

function start() {
    for (let i = 0; i < 2; i++)
        console.log(i);
    
    console.log(i);
}
start();
0
1
Uncaught ReferenceError: i is not defined 
    at start (<anonymous>:5:17)
    at <anonymous>:1:1
function start() {
    for (var i = 0; i < 2; i++)
        console.log(i);
    
    console.log(i);
}
start();  // In the output below you can see the 'var i' is not terminated when the 'for(...){...}'' block is finished
0
1
2

An­oth­er ex­am­ple how var is ac­ces­si­ble from out­side the block where it is de­fined.

function start() {
    for (let i = 0; i < 5; i++) {
        if (true) {
            var color = 'red';
        }
    }

    console.log(color);
}
start();
red

If we have used let color = 'red' the above code will throw an er­ror, but when we use var color = 'red' we can ac­cess the vari­able in­side the whole func­tion not on­ly with­in the if(…){…} scope.

Is­sue 2

The sec­ond is­sue with var is re­lat­ed to the Glob­al and the Lo­cal Scope – the vari­ables, de­fined by var are at­tached to the win­dow ob­ject (used by the browsers at the fron­tend).

var firstName = 'John';
let lastName = 'Smith';
console.log(window.firstName, window.lastName);
John undefined

Types

  • Prim­i­tives (val­ue types)
  • Ref­er­ence types (ob­jects, ar­rays, func­tions)

JavaScript is a dy­nam­ic lan­guage. Which means we can change the type of a vari­able dur­ing the script, un­like the sta­t­ic lan­guages where the de­fined vari­able type is con­stant and can­not be changed dur­ing the pro­gram.

Prim­i­tive types

The prim­i­tive types in JavaScript are:

  1. Strings
  2. Num­bers
  3. Booleans
  4. un­de­fined
  5. null
  6. Sym­bol
let name = 'Spas';          // String Literal
let age = 55;               // Number Literal
let isViewMode =  true;     // Boolean Literal (true/false)
let fullName = undefined;   // This is the default type of values in JavaScript
let lastName = null;
let mySymbol = Symbol('someDescription'); // Symbol value with description
A val­ue hav­ing the da­ta type Sym­bol can be called a “Sym­bol val­ue”. In a JavaScript run­time en­vi­ron­ment, a sym­bol val­ue is cre­at­ed by call­ing the glob­al func­tion Sym­bol(), which dy­nam­i­cal­ly pro­duces an anony­mous, unique val­ue. A sym­bol can be used as an ob­ject prop­er­ty. Sym­bol is not a full con­struc­tor. No­tice that there was no new Key­word. As Sym­bol is a prim­i­tive val­ue, if we at­tempt to cre­ate a sym­bol us­ing the new op­er­a­tor, the new op­er­a­tor throws a Type­Er­ror. We can pass a pa­ra­me­ter to Sym­bol(), and that is used as the sym­bol de­scrip­tion, use­ful just for de­bug­ging pur­pos­es.

The Num­bers could be in­te­ger or float­ing point num­bers, but their types are all num­bers.

let integer = 12;
typeof integer;   // "number"
let floating = 1.2;
typeof floating;  // "number"

Ref­er­ence types

The ref­er­ence types in JavaScript are:

  1. Ob­jects
  2. Ar­rays
  3. Func­tions

Ob­jects

The Ob­jects has:

  • Prop­er­ties – prim­i­tives de­fined by "keys": and "values",
  • Meth­ods – in­ter­nal functions() that op­er­ates with the prop­er­ties of the ob­ject.
let person = {};    // Object Literal
typeof person;      // "object"
let person = {
    "name": "Spas",
    "age":  55
};
console.log(person);
{name: "Spas", age: 55}

We can ac­cess the Prop­er­ties of an Ob­ject via:

  • Dot no­ta­tion: object.proprtyName
  • Brack­et no­ta­tion: object['proprtyName']
person.name = "Ivan";   // Assing a value to an object property via Dot notatin
person['age'] =  25;    // Assing a value to an object property via Bracket notatin
console.log(person);
{name: "Ivan", age: 25}

Us­ing Dot no­ta­tion is clean­er and eas­i­er, but the Brack­et no­ta­tion could be used when we want to pass vari­able in the place of the key – i.e. when when us­ing a loop or so.

let keyToPrint = 'name';
console.log(person[keyToPrint]);
Ivan

Ar­rays

JavaScript Ar­ray is a da­ta struc­ture that we use to rep­re­sent a list of items, in this count an item could be Prim­i­tives or Ob­jects. JavaScript Ar­rays can­not be mul­ti di­men­sion­al, but the can store Ob­jects in­stead Prim­i­tives – and can mix them.

let selectedItems = []; // Array Literal
typeof selectedItems;   // "object"

The JavaScript Ar­ray is (a kind of) Ob­ject and it has prop­er­ties and meth­ods (in­her­it­ed from its Pro­to­type). See the selectedItems.lenght ex­am­ple be­low.

let selectedItems = ['red', 'blue'];
console.log(selectedItems);
(2) ["red", "blue"]
console.log(selectedItems.length)
2

Each el­e­ment of an Ar­ray has an In­dex. The Ar­ray In­dex starts from 0. So the first el­e­ment has in­dex 0, the sec­ond el­e­ment has in­dex 1 and so on.

console.log(selectedItems[0], selectedItems[1]);
red blue

The JavaScript Ar­ray length is dy­nam­ic – we can change it. We can cre­ate a new in­dex el­e­ment and as­sign a val­ue in the fol­low­ing way:

selectedItems[2] = 'green'; // String
selectedItems[3] = 33;      // Number
selectedItems[4] = {};      // Object

Note in this ex­am­ple we have mixed the el­e­ment types.

console.log(selectedItems);
(5) ["red", "blue", "green", 33, {…}]

Func­tions

JavaScript Func­tions are sets of state­ments that per­forms a task or cal­cu­lates a val­ue. The Func­tions could have In­puts – could use (mul­ti­ple) pa­ra­me­ters – but it is not manda­to­ry.

function greet(parameter) {
    /** Body of the function **/
}
typeof greet;   // "function"
function greet(name) {   // 'name' is an input parameter of the function
    console.log('Hello ' + name);
}
greet('Nik');         // 'Nik' is an argument which become a value of the param. 'name'
Hello Nik

The func­tions could Change the val­ues of a glob­al vari­ables (ob­jects) or could Re­turn a val­ue.

function square(number) {
    return number * number;
}

The re­turned val­ue could be as­signed to a vari­able or ob­ject prop­er­ty.

let result = square(2);
console.log(result);
4

Sin­gle re­spon­si­bil­i­ty prin­ci­ple. Ac­cord­ing to this prin­ci­ple we should have func­tions that are small and fo­cused on­ly on one thing. Let's say we have a func­tion that cal­cu­late the av­er­age grade of a stu­dent.

const marks = [80, 90, 90];
function calculateGrade(marks) {
    let sum = 0;

    for (let mark of marks) sum += mark;
    
    let averageGrade = sum / marks.length;

    if (averageGrade < 60) return 'F';
    if (averageGrade < 70) return 'D';
    if (averageGrade < 80) return 'C';
    if (averageGrade < 90) return 'B';
    return 'A';
}
console.log(calculateGrade(marks));
B

By ap­ply­ing the Sin­gle re­spon­si­bil­i­ty prin­ci­ple we will have two small func­tions, one gener­ic func­tion that will cal­cu­late the av­er­age val­ue, and one oth­er func­tion that will map the re­sult.

function calculateGrade(marks) {
    let averageGrade = calculateAverage(marks);

    if (averageGrade < 60) return 'F';
    if (averageGrade < 70) return 'D';
    if (averageGrade < 80) return 'C';
    if (averageGrade < 90) return 'B';
    return 'A';
}

function calculateAverage(array) {
    let sum = 0;
    for (let value of array) sum += value;
   
    return sum / array.length;
}

Read al­so:

Garbage Col­lec­tor

In low lev­el lan­guages like C or C++, when cre­at­ing an ob­ject we need to al­lo­cate mem­o­ry to it, and when we're done we have to deal­lo­cate mem­o­ry. But in JavaScript we don't have this con­cept. We can eas­i­ly cre­ate a new ob­ject. At the time we ini­tial­ize this ob­ject, then mem­o­ry is au­to­mat­i­cal­ly al­lo­cat­ed to this ob­ject. Next, we can use that. And when we were done us­ing, we don't have to deal­lo­cate the mem­o­ry. So the JavaScript en­gine has what we call a garbage col­lec­tor.

The job of the garbage col­lec­tor is to find the vari­ables or con­stants that are no longer used and then deal­lo­cate the mem­o­ry that was al­lo­cat­ed to them ear­li­er. So you as a JavaScript de­vel­op­er do not have to wor­ry about this mem­o­ry al­lo­ca­tion. And the al­lo­ca­tion hap­pens au­to­mat­i­cal­ly be­hind the scene and you have no con­trol over that.

You can­not tell the garbage col­lec­tor when to run and what vari­ables to re­move from the mem­o­ry. So based on some com­plex al­go­rithms, this garbage col­lec­tor runs in the back­ground. It fig­ures out what vari­ables are not used and then it will au­to­mat­i­cal­ly deal­lo­cate their mem­o­ry.