n00b pro

01. Javascript Syntax

Dit hoofdstuk is onderdeel van de cursus Javascript. Andere cursussen in dezelfde reeks: HTML, CSS, C#, Ontwikkelomgeving.

Werken met Javascript

Javascript als scriptingtaal

Javascript is een scriptingtaal, geen echte programmeertaal zoals C#. Enkele kenmerken:

Javascript is syntactisch een erg rijke taal, die zeer compact kan zijn. Kopieer volgende fragment maar eens in een HTML document, en bekijk het resultaat...

<!doctype html>
<html lang="en">
<body>
   <canvas id="c"></canvas>
   <script>
      for(B=i=y=u=b=i=5-5,x=10,I=[],l=[];B++<304;I[B-1]=B%x?B/x%x<2|B%x<2?7:B/x&4?0:l[i++]="ECDFBDCEAAAAAAAAIIIIIIIIMKLNJLKM@G@TSb~?A6J57IKJT576,+-48HLSUmgukgg OJNMLK  IDHGFE".charCodeAt(y++)-64:7);function X(c,h,e,s){c^=8;for(var o,S,C,A,R,T,G,d=e&&X(c,0)>1e4,n,N=-1e8,O=20,K=78-h<<9;++O<99;)if((o=I[T=O])&&(G=o^c)<7){A=G--&2?8:4;C=o-9?l[61+G]:49;do if(!(R=I[T+=l[C]])&&!!G|A<3||(R+1^c)>9&&G|A>2){if(!(R-2&7))return K;n=G|(c?T>29:T<91)?o:6^c;S=(R&&l[R&7|32]*2-h-G)+(n-o?110:!G&&(A<2)+1);if(e>h||1<e&e==h&&S>2|d){I[T]=n;I[O]=0;S-=X(c,h+1,e,S-N);if(!(h||e-1|B-O|T-b|S<-1e4))return W(),c&&setTimeout("X(8,0,2),X(8,0,1)",75);I[O]=o;I[T]=R}if(S>N||!h&S==N&&Math.random()<.5)if(N=S,e>1)if(h?s-S<0:(B=O,b=T,0))break}while(!R&G>2||(T=O,(G||A>2|(c?O>78:O<41)&!R)&&++C*--A))}return-K+768<N|d&&N}function W(){i="<table>";for(u=18;u<99;document.body.innerHTML=i+=++u%x-9?"<th width=60 height=60 onclick='I[b="+u+"]>8?W():X(0,0,1)'style='font-size:50px'bgcolor=#"+(u-B?u*.9&1||9:"d")+"0f0e0>&#"+(I[u]?9808+l[67+I[u]]:160):u++&&"<tr>")B=b}W()
   </script>
</body>
</html>

Javascript heeft een lange voorgeschiedenis van naamgeving: oorspronkelijk Mocha gedoopt, dan LiveScript en vervolgens Javascript, om tenslotte hernoemd te worden naar de vandaag officiële naam ECMAScript of kortweg ES. Ook de versienummering is verwarrend: ECMAScript6 of ES6 (a.k.a. Harmony) wordt ook ES2015 genoemd, en komt ES7 dus overeen met ES2016.

Javascript in andere omgevingen

Javascript is enkel een taal, d.w.z. een set van syntaxregels; dit zegt niks over waar het uitgevoerd wordt. In principe kan het uitgevoerd worden in elke omgeving waar een Javascript engine op kan draaien. De meest gekende toepassing is in webpagina’s, maar enkele andere mogelijke omgevingen zijn:

In Windows Scripting Host

Je kan Javascript gebruiken om scripts uit te voeren in een Windows command. Codevoorbeeld (en ter vergelijking rechts de C# Console versie):

/* global WScript */
function faculteit(n) {
   var resultaat = n;
   for (var i = n - 1; i > 1; i--) resultaat *= i;
   return resultaat;
}
WScript.StdOut.WriteLine('FACULTEIT BEREKENEN');
WScript.StdOut.WriteLine('');
WScript.StdOut.Write('Geef een geheel getal: ');
var getal = parseInt(WScript.StdIn.ReadLine());
WScript.StdOut.Write('De faculteit is ' + faculteit(getal));

static private int Faculteit(int n) {
   int resultaat = n;
   for (int i = n - 1; i > 1; i--) resultaat *= i;
   return resultaat;
}
static void Main(string[] args) {
   Console.WriteLine("FACULTEIT BEREKENEN");
   Console.WriteLine();
   Console.Write("Geef een geheel getal: ");
   int getal = Convert.ToInt32(Console.ReadLine());
   Console.WriteLine($"De faculteit is {Faculteit(getal)}");
}

Sla het script op als demoWSH.js, en run het met het cscript commando in een command prompt:

C:\Users\rogie\Desktop>cscript demoWSH.js
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

FACULTEIT BEREKENEN

Geef een geheel getal: 8
De faculteit is 40320
C:\Users\rogie\Desktop
resultaat in de command prompt

Serverside Javascript met NodeJS

NodeJS is een Javascript runtime omgeving waarmee Javascript buiten de browser kan uitgevoerd worden, bijvoorbeeld om server- of desktop toepassingen te schrijven. Je moet het eerst downloaden en installeren via https://nodejs.org/en Voorbeeldscript voor het opzetten van een eenvoudige server:

const http = require('http');
const port = 8124;
const status = 200;
http.createServer(function(request, response) {
   response.writeHead(status, {'Content-Type': 'text/plain'});
   response.end('Hello World\n');
}).listen(port);
console.log('Server running at http://127.0.0.1:8124/');

Sla dit script ergens op, bijvoorbeeld als demoNode.js op de desktop. Voer het dan uit met het node commando:

C:\Users\rogie\Destkop>node demoNode.js
Server running at http://127.0.0.1:8124/
run het script in de command prompt

Je kan vervolgens het serveradres openen in de browser:

array

Javascript in een webpagina

Extern script

In de rest van de cursus beperken we ons tot Javascript in web pagina’s. De werkwijze is gelijkend aan hoe je CSS aan een webpagina toevoegt:

  1. maak een map 'js' in je project
  2. maak daarin een bestand 'script.js'
  3. link het onderaan in de <body> (CSS bestanden link je bovenaan in de <head>) je HTML document met <script src="js/scripts.js"></script>
  4. open de HTML pagina in de browser (bijvoorbeeld met de Go Live knop rechtsonder)

Link je scripts altijd onderaan in de body, zodat alle HTML ingelezen is vóór het script uitgevoerd wordt! Als bonus krijgt de gebruiker dan sneller de inhoud van de pagina te zien, zonder eerst op het inladen van het script te moeten wachten

Voorbeeldcode, HTML en Javascript en het resultaat in de webpagina:

document.getElementById('message').innerHTML = 'Hallo Wereld!';
console.log('einde script');
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Hello World demo</title>
</head>
<body>
   <p id="message"></p>
   <script src="js/scripts.js"></script>
</body>
</html>

Net zoals bij CSS, kan je ook meerdere scripts linken. Een typisch HTML bestand wordt dan:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Hello World demo</title>
   <link rel="stylesheet" src="common/vendor/fancybox.min.css">
   <link rel="stylesheet" src="common/vendor/owlcarousel.min.css">
   <link rel="stylesheet" src="common/vendor/owlcarousel.theme.min.css">
   <link rel="stylesheet" src="css/start.css">
   <link rel="stylesheet" src="css/styles.css">
</head>
<body>
   ...
   <script src="common/vendor/fancybox.js"></script>
   <script src="common/vendor/owlcarousel.js"></script>
   <script src="js/library.js"></script>
   <script src="js/scripts.js"></script>
</body>
</html>

Intern scriptblok

In principe kan je scripts ook in de HTML pagina plaatsen, en net zoals bij CSS

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Hello World demo</title>
</head>
<body>
   <p id="message"></p>
   <script>
      document.querySelector('#message').innerHTML = 'Hallo Wereld!';
      console.log('einde script');
   </script>
</body>
</html>

Inline script

Je kan scripts zelfs inline plaatsen, en net zoals bij CSS:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Hello World demo</title>
</head>
<body>
   <input type="button" value="I'm a button" onclick="console.log('auch')">
</body>
</html>

Inline scripts zijn NOT DONE. Als je dit tegenkomt op het Internet, neem het dan niet over in een oefening of project!

Javascript console

In de inspector van Chrome (F12 of Shift-Ctrl-I) vind je onder het tabblad "Console" allerlei browser berichten: fouten, waarschuwingen, meldingen... Je kan er ook zelf naar schrijven, wat de Console tot een debugging instrument bij uitstek maakt.

Browsermeldingen

Javascript foutmeldingen komen in de Console terecht, dus hou het altijd goed in de gaten!

document.querySelector('#messge').innerHTML = 'Hallo Wereld!'; // FOUT: element met id "messge" bestaat niet
console.log('einde script');

Zelf schrijven naar de console

Je kan met console.log() teksten naar de console schrijven:

const name = 'Rogier';
console.log(`Hello ${name}`);
resultaat in de console

Je kan het ook gebruiken om variabelen of zelfs hele arrays of objecten te inspecteren:

const names = ['Alice', 'Bob', 'Clive'];
const person = { name: 'rogier', age: '46', isMale: true};
console.log(person);
console.log(names);
resultaat in de console

Er zijn trouwens nog een hele waslijst andere functies voor console (volledige lijst zie https://developer.chrome.com/docs/devtools/console/api):

console.table({ name: 'rogier', age: '46', isMale: true});
console.warn('this is a serious warning');
console.error('whoops! an error occured');
resultaat in de console

Console opmaak

Met de placeholder %c kan je de weergave in de console stijlen. Alles na %c krijgt de CSS die je als volgende argument meegeeft:

console.log('%c Let op!', 'background: #f00; color: #fff; font-size: 20px; padding: 4px;');
resultaat in de console

Je kan ook meerdere %c-placeholders in één bericht gebruiken. Elk stuk tekst krijgt dan de CSS van het volgende argument, zodat je bijvoorbeeld een deel van een zin vet of in kleur kunt zetten:

console.log('Let op dat je %c alleen geziene technieken %c gebruikt.', 'font-weight: bold; color: #0a0;', 'font-weight: normal;');
resultaat in de console

Zo kan je bijvoorbeeld waarschuwingen of foutmeldingen visueel laten opvallen zonder console.warn() of console.error() te gebruiken.

debugger

De console werkt asynchroon. Dit is een belangrijk begrip in programmeren in het algemeen, en Javascript in het bijzonder. Het betekent kortweg dat je niet precies weet in welke volgorde instructies uitgevoerd worden (meer hierover later in hoofdstuk 05. asynchrone javascript). Dat heeft in de console onverwachte gevolgen. Neem volgende code:

const person = {
   name: 'Rogier',
   age: 42
};
console.log(person); // schrijf 'person' naar de console
person.age = 54; // verander achteraf de waarde 'age' naar 54

In de console zie je de waarde '54' staan die pas ingesteld is nádat console.log() opgeroepen werd.

De reden is dat waarden in de console niet noodzakelijk verschijnen op het moment in de code waarop console.log() opgeroepen wordt. Je kan handmatig het script pauzeren met debugger, en dan klopt de waarde wel:

let person = {
   name: 'Rogier',
   age: 42
};
console.log(person); // schrijf 'person' naar de console
debugger; // pauzeer het script
person.age = 54; // verander achteraf de waarde 'age' naar 54

De weergegeven waarde is nu wel correct:

Variabelen, types & constanten

Variabelen

Variabelen aanmaken is veel eenvoudiger dan in C#: je gebruikt gewoon het gereserveerd woord let. Een vergelijking voor de meest voorkomende types:

let num1 = 3; // geheel getal
let num2 = 3.14; // kommagetal
let boo = true; // boolean
let str = 'hello'; // string
let arr = [1, 2, 3, 5, 8, 13]; // array
let dat = new Date(); // Date object
let me = { age: 54, name: 'Rogier' };  // anoniem object
int num1 = 3; // geheel getal
double num2 = 3.14; // kommagetal
bool boo = true; // boolean
string str = "hello"; // string
int[] arr = new int[] { 1, 2, 3, 5, 8, 13 }; // array
DateTime dat = new DateTime(); // DateTime object
var me = new { Age = 54, Name = "Rogier" }; // anoniem object

In veel (oude) Javascript code zul je nog var zien gebruiken in plaats van let.

var num1 = 3; // geheel getal
var num2 = 3.14; // kommagetal
...

Weak typing van variabelen

Variabelen in Javascript zijn weakly typed, d.w.z. het type kan veranderen als je er een andere waarde aan toewijst:

let num = 3; // num is een getal
num = 'Rogier'; // num is nu een string
num = false; // num is nu een boolean
int num = 3; // num is een getal
num = "Rogier"; // FOUT!
num = false; // FOUT!

Mixen van variabelen

Als je verschillende types variabelen mixt in één expressie, passen zowel Javascript als C# in bepaalde gevallen automatische conversie toe. Javascript is daarin nog een flexibeler dan C#. De verschillen zijn echter groot, zoals uit onderstaande vergelijking blijkt:

console.log(3 + '2'); // 32; 3 omgezet naar string
console.log(3 + "2"); // 32; 3 omgezet naar string
console.log(3 * '2'); // 6; '2' omgezet naar getal
console.log(3 * "2"); // 6; "2" omgezet naar getal
console.log(3 - '2'); // 1; '2' omgezet naar getal
console.log(3 - "2"); // 1; "2" omgezet naar getal
console.log(3 == '3.0'); // true; '3.0' omgezet naar getal
console.log(3 / 2); // 1.5; gewone deling
console.log(3.0 / 2); // 1.5; gewone deling
Console.WriteLine(3 + '2'); // 53; '2' omgezet naar ASCII 50
Console.WriteLine(3 + "2"); // 32; 3 naar string omgezet
Console.WriteLine(3 * '2'); // 150; '2' omgezet naar ASCII 50
Console.WriteLine(3 * "2"); // FOUT!
Console.WriteLine(3 - '2'); // -47; '2' omgezet naar ASCII 50
Console.WriteLine(3 - "2"); // FOUT!
Console.WriteLine(3 == '3.0'); // FOUT!
Console.WriteLine(3 / 2); // 1; gehele deling
Console.WriteLine(3.0 / 2); // 1.5; gewone deling

Conversie van variabelen

Pas daarom bij het mixen van types in één expressie altijd conversie toe:

const test = 3;
console.log(test + parseInt('2')); // 5
console.log(test.toString() + '2'); // 32
console.log(parseFloat(test) / 2); // 1.5
int test = 3;
Console.WriteLine(test + Convert.ToInt32("2")); // 5
Console.WriteLine(Convert.ToString(test) + '2'); // 32
Console.WriteLine(Convert.ToDouble(test) / 2); // 1.5

Identity operator

Er is een verschil tussen de identity operator === (vergelijkt waarde én type) en de equals operator == (vergelijkt enkel waarden):

console.log('3' == 3); // true
console.log('3' === 3); // false; verschillende types
console.log('' == false); // true
console.log('' === false); // false; verschillende types

Infinity, NaN, undefined

Javascript heeft drie waarden die C# niet kent: Infinity (oneindig), NaN (Not a Number of “geen getal”) en undefined (waarde onbekend)

let test1;
console.log(test1); // undefined
console.log(7 * "bladibla"); // NaN
console.log(6 / 0); // Infinity
int test1;
Console.WriteLine(test1); // fout! variabele heeft geen waarde
Console.WriteLine(7 * "bladibla"); // fout! mixen van types
Console.WriteLine(6 / 0); // fout! deling door 0

Constanten

Een variabele declareer je als constante met const. Het betekent dat je geen nieuwe waarde mag toekennen. Bij samengestelde types als objecten, arrays, lijsten enz... kan je wel nog steeds de individuele elementen of properties aanpassen. Ter illustratie:

const test1 = "abc";
const test2 = 123;
const test3 = [ 12, 9, 4, 33 ];
const test4 = new Date(1970, 6, 23);

test3[1] = 10; // aanpassing één element; ok
test4.setFullYear(1971); // aanpassing één property; ok

test1 = "xyz" // FOUT! variabele overschrijven mag niet
test2 = 456; // FOUT! variabele overschrijven mag niet
test3 = [ 55, 67, 3 ]; // FOUT! variabele overschrijven mag niet
test4 = new Date(1972, 8, 12); // FOUT! variabele overschrijven mag niet

const, let of var?

De afspraken zijn:

Onthoud dus deze regel: const wanneer mogelijk!

Qua hooflettergebruik voor constanten mag je vrij kiezen tussen UPPERCASE_UNDERSCORE en camelCase notatie. En mogelijke keuze is de eerste notatie enkel voor “echte” constanten als MAX_POGINGEN of CANVAS_WIDTH te gebruiken, en de tweede voor constanten die eigenlijk variabelen zijn die toevallig maar één keer toegewezen worden, zoals familieNaam of boodschappenLijst.

Strings

Drie soorten quotes

In C# moet je dubbele quotes gebruiken voor strings, maar in Javascript kan je ook enkele quotes of backticks gebruiken. Een vergelijking:

let first = 'Rogier'; // enkele quotes
let last = "van der Linde"; // dubbele quotes
let greet1 = 'Zeg "Welkom"'; // enkel en dubbel genest
let greet2 = "Zeg 'Welkom'"; // omgekeerd mag ook
let message = `Welkom ${first} ${last}`; // string interpolatie: gebruik backticks
string first = "Rogier";
string last = "van der Linde";
string greet1 = "Zeg \"Hallo\""; // escape nodig
string greet2 = "Zeg 'Hallo'"; // geen escape nodig
string message = $"Hallo {first} {last}"; // string interpolatie

String interpolatie, multiline strings

Net zoals C# kent Javascript string interpolatie en multiline strings. In C# worden ze met $ reps. @ aangeduid, in javascript met backticks:

// string interpolatie
let name = 'Rogier';
console.log(`Welkom ${name}`);

// multiline string
console.log(`Een
twee
drie
vier
hoedje van
hoedje van...`);
// string interpolatie
string naam = "Rogier";
Console.WriteLine($"hallo {naam}");

// multiline string
Console.WriteLine(@"Een
twee
drie
vier
hoedje van
hoedje van...");

String methodes en properties

property/methode Omschrijving
length aantal karakters van de string
endsWith(str) controleert of een string eindigt met een stuk tekst
includes(str) controleert of een string een stuk tekst bevat
indexOf(str) zoek de positie van een waarde (-1 indien niet gevonden)
replace(str1, str2) vervangt de eerst gevonden str1 door str2
replaceAll(str1, str2) vervangt alle gevonden str1 door str2
split(separator) splitst een tekst in een array
startsWith(str) controleert of een string begint met een stuk tekst
substr(start, num) substring beginnende van positie start en num karakters
substring(start, end) substring van posities start tot end
toLowerCase() zet om naar kleine letters
toUpperCase() zet om naar hoofdletters
trim() verwijder spaties aan begin en einde

Enkele voorbeelden:

console.log('ha'.repeat(3)); // hahaha
console.log('yes we can'.split(' ')) // ['yes', 'we', 'can']
console.log('hello'.startsWith('hell')); // true
console.log('hello'.includes('ell')); // true

Arrays

Declaratie en gebruik

Vergelijking van arrays in Javascript en C#:

const arr1 = [];
arr1[0] = 'abc';
arr1[1] = 'def';
console.log(arr1.length); // 2
string[] arr1 = new string[10];
arr1[0] = "abc";
arr1[1] = "def";
Console.WriteLine(arr1.Length); // 10

Arrays in Javascript zijn veel losser dan in C#. Je mag types mixen, en elementen toevoegen waar je wil, zonder risico op overflow fouten:

arr1[1] = 12; // getal toevoegen
arr1[2] = false; // boolean toevoegen: ok
arr1[100] = 'test'; // tekst toevoegen: ok
console.log(arr1.length); // 101
arr1[1] = 12; // fout! is geen string
arr1[2] = false; // fout! is geen string
arr1[100] = "test"; // fout! buiten het bereik

Properties en methodes

property/methode Omschrijving
length aantal elementen van de array
includes() controleert of de rij een waarde bevat
indexOf() zoek een waarde en geef eerste index terug (-1 indien niet gevonden)
join() voeg elementen samen tot een string
pop() verwijder en return element achteraan de rij
push() voeg element toe achteraan de rij
shift() verwijder en return element aan het begin de rij

Voorbeeldfragment:

const list1 = ['boter', 'kaas', 'melk'];
list1.push('eieren'); // voeg item toe
list1.push('tomaten'); // voeg item toe
if (list1.includes('kaas')) console.log('lijst bevat kaas');
console.log(`lijst bevat ${list1.length} items`); // 5
const first = list1.pop(); // verwijder laatste (tomaten)
const last = list1.shift(); // verwijder eerste (boter)
list1.reverse(); // keer volgorde om
console.log(`lijst: ${list1.join(', ')}`); // eieren, melk, kaas

Extensiemethodes

Net zoals in veel andere programmeertalen, kent Javascript een aantal zgn. extensiemethodes voor arrays. De interessantste zijn find(), filter() en map(). Een codevoorbeeld:

const arr1 = ['boter', 'kaas', 'melk', 'eieren'];
console.log(arr1.find(str => str.startsWith('k'))); // 'kaas'
console.log(arr1.filter(str => str.length > 4 )); // ['boter', 'eieren']
console.log(arr1.map(str => str.length )); // [5, 4, 4, 6]

const arr2 = [16, -77, 3, 4, -9 ];
console.log(arr2.find(n => n > 0 && n < 10 )); // 3
console.log(arr2.filter(n => n % 2 == 0)); // [16, 4]
console.log(arr2.map(el => el + 1 )); // [17, -76, 4, 5, -8]

Objecten

Een object groepeert gerelateerde gegevens als key-value paren. Je kan properties opvragen met punt-notatie of met vierkante haken.

const student = {
   voornaam: 'Mia',
   achternaam: 'Verhaeghe',
   leeftijd: 19
};

console.log(student); // { voornaam: 'Mia', achternaam: 'Verhaeghe', leeftijd: 20 }
console.log(student.voornaam); // 'Mia', dot notatie
console.log(student['achternaam']); // 'Verhaeghe', vierkante haken notatie
student.leeftijd = 20; // property aanpassen

Een key-value paar kan zelfs een functie zijn:

const myCar = {
   make: 'Mercury Bobcat',
   speed: 0,
   engineOn: true,
   constructionDate: new Date(1976, 6, 24),
   accelerate: function(acc) {
      if (this.engineOn) speed += acc;
   }
}

myCar.accelerate(25);
console.log(`current speed is ${myCar.speed}`);

Objecten als parameter

Objecten worden vaak gebruikt om properties in één variabele te groeperen, die dan makkelijk als parameter kan doorgegeven worden:

// functie met één 'thing' parameter
function getDescription(thing) {
   const lines = [];
   lines.push(`Name: ${thing.kind}`);
   lines.push(`Color: ${thing.color}`);
   lines.push(`It weighs ${thing.volume * thing.density}kg`);
   return lines.join('\n');
}

// stel het object samen
const stone = {
   kind: 'lapis lazuli',
   volume: 0.03, // m³
   density: 3000, // kg/m³
   color: 'darkblue'
}

// geef het door aan de functie
console.log(getDescription(stone));

Anonieme objecten

Net zoals bij anonieme functies, kan je ook ad hoc objecten aanmaken en meegeven zonder ze eerst een naam te geven:

// functie met één 'thing' parameter
function getDescription(thing) {
   const lines = [];
   lines.push(`Name: ${thing.kind}`);
   lines.push(`Color: ${thing.color}`);
   lines.push(`It weighs ${thing.volume * thing.density}kg`);
   return lines.join('\n');
}

// geef een anoniem object door aan de functie
console.log(getDescription({
   kind: 'lapis lazuli',
   volume: 0.03, // m³
   density: 3000, // kg/m³
   color: 'darkblue'
}));

Spread operator

De spread operator ... "spreidt" de elementen van een itereerbaar object zoals een array of string.

Voorbeeld voor het samenvoegen van arrays:

const a = [1, 2, 3];
const b = [4, 5, 6];
const samen = [...a, ...b];
console.log(samen); // [1, 2, 3, 4, 5, 6]

Array kopiëren met spread operator:

const origineel = [1, 2, 3];
const kopie = [...origineel];
kopie.push(4);
console.log(origineel); // [1, 2, 3]
console.log(kopie);     // [1, 2, 3, 4]

String omzetten naar array van tekens met spread operator:

const woord = 'hallo';
const chars = [...woord];
console.log(chars); // ['h', 'a', 'l', 'l', 'o']

Array als parameters aan een functie meegeven met spread operator:

const getallen = [3, 7, 2, 9];
const max = Math.max(...getallen);
console.log(max); // 9

Zonder spread zou Math.max(getallen) NaN geven, omdat je dan één array doorgeeft in plaats van vier aparte getallen.

Selecties en iteraties

Selecties

In Javascript komt de syntax van de selecties if, if-else en switch-case overeen met C#. Een if-else voorbeeld:

const badGrades = true;
if (badGrades) {
   console.log('House arrest for two weeks');
} else {
   console.log('No house arrest');
}
bool badGrades = true;
if (badGrades) {
   Console.WriteLine("House arrest for two weeks");
} else {
   Console.WriteLine("No house arrest");
}

Vergeet ook de handige ternaire operator niet:

const number = 13;
console.log(`${number} is ${number % 2 == 0 ? 'even' : 'odd'}`);
int number = 13;
Console.WriteLine($"{number} is {(number % 2 == 0 ? "even" : "odd")}");

Iteraties

herhalingsstructuren while, do-while, for

In Javascript komt de syntax van de selecties while, do-while en for overeen met C#. Een for voorbeeld:

// definieer een array
const forrestFriends = ['Bubba', 'Lt. Dan'];

// itereer over de waarden
for (let i = 0; i < forrestFriends.length; i++) {
   console.log(`friend nr. ${i}: ${forrestFriends[i]}`);
}
// definieer een array
string[] forrestFriends = { "Bubba", "Lt. Dan" };

// itereer over de waarden
for (int i = 0; i < forrestFriends.Length; i++) {
   Console.WriteLine($"friend number {i}: {forrestFriends[i]}");
}

itereren over arrays met for-of

De for-of iteratie in Javascript komt overeen met foreach-in in C#:

// definieer een array
const forrestFriends = ['Bubba', 'Lt. Dan'];

// itereer over de waarden
for (const friend of forrestFriends) {
   console.log(friend); // Bubba, Lt. Dan
}
// defininieer een array
string[] forrestFriends = { "Bubba", "Lt. Dan" };

// itereer over de waarden
foreach (string friend in forrestFriends) {
   Console.WriteLine(friend); // Bubba, Lt. Dan
}

itereren over collecties met forEach

Javascript heeft nog een verkorte notatie (zonder C# equivalent) die velen zeer handig vinden:

// definieer een array
const forrestFriends = ['Bubba', 'Lt. Dan'];

// itereer over de waarden
forrestFriends.forEach(friend => {
   console.log(friend); // Bubba, Lt. Dan
});

Functies

Klassieke notatie

Methodes in C# noemt men in Javascript functies. Een vergelijking van de syntax:

function getFibonacciNumbers(n) {
   if (n <= 0) return [];
   if (n == 1) return [0];
   const arrFib = [];
   arrFib[0] = 0;
   arrFib[1] = 1;
   for (let i = 2; i < n; i++) {
      arrFib[i] = arrFib[i - 2] + arrFib[i - 1];
   }
   return arrFib;
}
private static int[] GetFibonacciNumbers(int n) {
   if (n <= 0) return new int[0] { };
   if (n == 1) return new int[1] { 0 };
   int[] arrFib = new int[n];
   arrFib[0] = 0;
   arrFib[1] = 1;
   for (int i = 2; i < n; i++) {
      arrFib[i] = arrFib[i - 2] + arrFib[i - 1];
   }
   return arrFib;
}

Notatie als constante

Je kan in Javascript een methode ook noteren als constante. Volgende notaties zijn gelijkwaardig (of toch bijna, er is een klein verschil, maar dat is voor deze cursus niet zo belangrijk)

const getFibonacciNumbers = function(n) {
   ...
}
function getFibonacciNumbers(n) {
   ...
}

Arrow expression notatie

Een verkorte notatie die je in nog andere talen tegenkomt, is de (...) => { ... } vorm. Volgende notaties zijn gelijkwaardig:

const getFibonacciNumbers = function(n) {
   ...
}
const bepaalGgd = function(get1, get2) {
   ...
}
const getFibonacciNumbers = n => {
   ...
}
const bepaalGgd = (get1, get2) => {
      ...
}

Optionele parameters

Je kan net zoals in C# standaardwaarden instellen voor parameters. Waar je geen waarden opgeeft, worden standaardwaarden genomen:

function orderDetails(verkoper, product, prijs, klant = null, aantal = 1, kortingPerc = 0) {
    return `
Verkoper: ${verkoper}
Klant: ${(klant == null ? '(onbekend)' : klant)}
Verkoop: ${aantal} x ${product}
Korting: ${(kortingPerc == 0 ? 'geen' : kortingPerc + '%')}
Te betalen: ${Math.round(prijs * aantal * (100 - kortingPerc) / 100, 2)} euro`;
}

console.log(orderDetails('Gift shop', 'Red Mug', 12.5));

Functies als parameters

Aangezien je functies als variabelen (of constanten) kan noteren, kan je ze ook als argument meegeven aan functies:

// declareer methode end()
function end() {
   console.log('Ok, that was funny 😄');
}

// declareer methode speak(), die als laatste parameter een functie 'callback' accepteert
function speak(quote, callback) {
   console.log(quote);
   callback(); // voer de tweede parameter uit
}

// roep speak() op met end() als argument
speak('Behind every great man is a woman rolling her eyes.', end);

Anonieme functies

Je kan trouwens ook rechtstreeks een methode meegeven, b.v. met de arrow expression notatie:

// declareer methode speak(), die als laatste parameter een functie 'callback' accepteert
function speak(quote, callback) {
   console.log(quote);
   callback(); // voer de tweede parameter uit
}

// roep speak() op met een arrow expression functie als laatste argument
speak('Behind every great man is a woman rolling her eyes.', () => {
   console.log('Ok, that was funny 😄');
});

Ingebouwde klassen: Math, Date, Array...

Minder dan C#, maar Javascript heeft ook een aantal ingebouwde klassen als Math, Date, Array... De syntax verschilt helaas vaak veel. Een paar typische voorbeelden:

// Date example
const now = new Date();
console.log(now.getFullYear());

// Math example
console.log(Math.ceil(Math.random() * 10));

// Array example
const arr1 = [ 'melk', 'boter', 'eieren' ];
arr1.sort();
console.log(arr1.join(', '));
// Date example
DateTime now = DateTime.Now;
Console.WriteLine(now.Year);

// Math/Random example
Random rnd = new Random();
Console.WriteLine(Math.Ceiling(rnd.Next() * 10.0));

// Array example
string[] arr1 = { "melk", "boter", "eieren" }
Array.Sort(arr1);
Console.WriteLine(String.Join(", ", arr1));

Stijlregels

Algemeen

accolades

Als je code block uit één regel bestaat, mag je in theorie de accolades weglaten. Dit is een slechte stijl, dus schrijf altijd de accolades voluit:

if (age < 6)
   console.log('child');
else if (age < 18)
   console.log('junior');
else
   console.log('adult');

if (age < 6) {
   console.log('child');
} else if (age < 18) {
   console.log('junior');
} else {
   console.log('adult');
}

code commentaar

Voorzie je code rijkelijk van commentaar. Zo blijft het leesbaar voor jou en je collega’s, vandaag en in de toekomst! Inspireer je op volgend voorbeeld:

/*
 * Binary sudoku script
 *
 * @author Rogier van der Linde <rogier.vanderlinde@odisee.be>
 */

// ===========================================
// DOM
// ===========================================

// create DOM shorthands
const divLoginModal = document.querySelector('#loginmodal');
const lnkLogin = document.querySelector('#lnkLogin');
const btnReset = document.querySelector('#btnReset');
...


// ===========================================
// FUNCTIONS
// ===========================================

/**
* Draws the sudoku board
*
* @param {number} width - board width
* @param {number} height - board height
* @param {array<number>} numbers one dimensional array of numbers
* @returns {string} string representation of the board
*/
function drawBoard(width, height, numbers) {
  ...
}

/**
* Shows login modal
*
* @param {object} e - event sender
*/
function showLogin(e) {
  e.preventDefault();
  divLoginModal.classList.add('show');
}

....

// ===========================================
// EVENTS
// ===========================================

// add event listeners
btnReset.addEventListener('click', drawBoard);
lnkLogin.addEventListener('click', showLogin);
....

code layout

Een paar van de belangrijkere regels:

console.log ('Genereer random getal... ' );
let random = Math.Random( ); let g1 =parseInt(random);
console.log(`Het kwadraat is: ${g1*g1}`);
console.log('Genereer random getal... ');
let random = Math.random();
let g1 = parseInt(random);
console.log(`Het kwadraat is: ${g1 * g1}`);

naamgeving

Regels voor naamgeving:

nesting

Vermijd nesting als het eenvoudig anders kan:

if (age > 6) {
   if (age < 18) {
      console.log('junior');
   } else {
      console.log('adult');
   }
} else {
   console.log('child');
}
if (age < 6) {
   console.log('child');
} else if (age < 18) {
   console.log('junior');
} else {
   console.log('adult');
}
pyramid of doom
vermijd de pyramid of doom!

JavaScript specifiek

hoofdlettergebruik

De gewoontes in Javascript qua hoofdlettergebruik en benaming verschillen lichtjes van C#. Een vergelijking:

  Javascript C#
variabelen camelCase, bv grootsteGetal idem
constanten SCREAMING_SNAKE_CASE of camelCase, b.v. MAX_ITEMS of maxItems PascalCase, bv MaxItems
methoden (C#) / functies (Javascript) camelCase, bv. berekenGemiddelde() PascalCase, bv. BerekenGemiddelde()
klassen (C#) / objecten (Javascript) PascalCase, bv Rectangle idem

quote gebruik

Voor strings in Javascript zijn er drie mogelijkheden. Houd je aan deze conventie:

const naam = 'Rogier';                   // standaard: enkele quotes
const groet = `Hallo ${naam}!`;          // backticks voor interpolatie
const tekst = `Dit is een lange zin
die over meerdere 
regels loopt.`;                          // backticks voor multiline

const, let of var?

Variabelen declareer je met const, let of var. Houd je aan deze conventie:

const PI = 3.14;                 // constant: nooit opnieuw toewijzen
const naam = 'Rogier';           // maak constant als deze waarde later niet meer verandert
const items = []; items.push(1); // constant: elementen toevoegen of verwijderen is geen nieuwe toewijzing
let teller = 0; teller++;        // moet let zijn: waarde wordt opnieuw toegewezen
let antwoord; antwoord = 'nee';  // moet let zijn: waarde wordt later toegewezen

strict equality (=== en !==)

Gebruik bij voorkeur === en !==, nooit == of !=. Die laatste doen automatische typeconversie, wat tot onverwachte bugs leidt:

console.log(3 == '3');   // true — string wordt omgezet naar getal
console.log(3 === '3');  // false — verschillende types
console.log(0 == false); // true — beide "falsy"
console.log(0 === false); // false

puntkomma's

Schrijf altijd een puntkomma aan het einde van elke statement:

const naam = 'Rogier'
console.log(naam)
const naam = 'Rogier';
console.log(naam);

geen magic numbers

Definieer constanten voor getallen die een betekenis hebben. Zo blijft de code leesbaar en makkelijker aan te passen:

if (items.length >= 10) { ... }
for (let i = 0; i < 7; i++) { ... }
const MAX_ITEMS = 10;
const DAGEN_PER_WEEK = 7;
if (items.length >= MAX_ITEMS) { ... }
for (let i = 0; i < DAGEN_PER_WEEK; i++) { ... }