Vuonna 2025 tulee kuluneeksi 10 vuotta Javascript-ohjelmointikielen merkittävästä virstaanpylväästä: silloin julkaistiin Javascript kielen päivitys, joka sai nimekseen ES6 tai toiselta nimeltään ECMAScript 2015.
Miksi kyseessä oli merkittävä päivitys? Koska silloin luotiin monet merkittävät käytännöt, jotka kehittivät Javasciptistä paljon käytettävämmän ohjelmointikielen. Nämä uudistukset ovat edelleen 10 vuoden jälkeen keskeisessä osassa Javascript -ohjelmointia.
Käymme tässä artikkelissa läpi ES6 -päivityksen merkittävimpiä muutoksia.
Muuttujien määrittely let ja const -määrityksillä
Aikaisemmissa versioissa Javascript-muuttuja määritettiin yleisesti ottaen var -määrityksellä. Siinä oli kuitenkin muutamia ongelmia, kuten lohkon sisäisen skoopin puuttuminen. Muuttuja oli silloin ns. ”globaali” muuttuja.
Uusi tapa muuttujien määrittelyyn tarjoaa paremman muuttujien hallinnan ja suojaa muuttujia asettamalla niille lohkon sisäisen skoopin, jolloin muuttuja ei näy ohjelmakoodissa ”liian kauas”.
let: Määrittelee muuttujan, jonka arvoa voidaan muuttaa, ja sillä on lohkon sisäinen skooppiconst: Määrittelee vakion, jonka arvoa ei voida muuttaa, ja sillä on myös lohkon sisäinen skooppi
Nuolifunktiot (arrow functions)
Lyhyempi syntaksi funktioiden määrittelyyn, joka tekee koodista selkeämpää ja helpommin luettavaa. Erityisesti niistä on iloa lyhyiden funktioiden määrittelyssä, jolloin koko funktio voidaan määritellä yhdelle riville.
Esimerkki
Vanha toteutus (ES5):
function sum(a, b) {
return a + b;
}
Uusi toteutus (ES6):
const sum = (a, b) => a + b;
Lupaukset (promises)
Lupaukset (promises) tarjoavat tehokkaan tavan käsitellä asynkronisia operaatioita, kuten API-kutsuja, tiedostonlukua ja muita viiveellisiä toimintoja. Ne myös tekevät koodista yksinkertaisempaa.
Promise on olio, joka edustaa asynkronisen operaation lopullista tulosta. Asynkroninen operaatio on tehtävä, joka suoritetaan taustalla ilman, että se estää pääohjelman suoritusta. Tämä tarkoittaa, että ohjelma voi jatkaa muiden tehtävien suorittamista samalla, kun asynkroninen operaatio odottaa valmistumistaan.
Promise voi olla kolmessa tilassa:
- Pending (odottava): Alkuperäinen tila, jossa lopputulosta ei ole vielä määritelty
- Fulfilled (täytetty): Operaation onnistunut suoritus, joka palauttaa arvon
- Rejected (hylätty): Operaation epäonnistuminen, joka palauttaa syyn (yleensä virheen)
Asynkroniset operaatiot ovat erityisen hyödyllisiä, kun suoritetaan tehtäviä, jotka voivat kestää kauan, kuten verkkopyyntöjä, tiedostonlukua tai ajastettuja tapahtumia.
Promise-käsittelyyn käytetään then, catch ja finally -metodeja:
promise
.then(result => {
console.log(result); // "Operation successful!"
})
.catch(error => {
console.error(error); // "Operation failed."
})
.finally(() => {
console.log("Operation completed.");
});
Ennen ES6:ta JavaScriptissä käsiteltiin asynkronisia operaatioita pääasiassa käyttämällä callback-funktioita. Niissä oli kuitenkin omat hankaluutensa, kuten ns. ”callback hell” jossa callbackit kertyvät syvälle toistensa sisään, tehden koodista vaikeasti luettavaa ja ylläpidettävää.
Luokat (classes)
Nykyään luokkien tukea olio-ohjelmoinnissa pidetään oikeastaan itsestään selvyytenä, mutta Javascriptiin luokat tulivat ES6:n mukana.
Ennen ES6:ta JavaScriptissä ei ollut luokkia sellaisina kuin ne nykyään tunnetaan. Sen sijaan käytettiin prototyyppipohjaista perintää ja funktiokonstruktoreita olioiden ja niiden käyttäytymisen määrittelyyn. Tämä tapa saattoi kuitenkin olla hieman monimutkainen ja vaikeasti ymmärrettävä ainakin niille ohjelmoijille, jotka olivat tottuneet käyttämään luokkia.
Moduulit (modules)
Mahdollistavat koodin jakamisen pienempiin, uudelleenkäytettäviin osiin, mikä parantaa koodin hallittavuutta ja uudelleenkäytettävyyttä. Moduulit käyttävät export ja import -avainsanoja ominaisuuksien ja funktioiden jakamiseen tiedostojen välillä.
ES6-moduulien sijasta Javascriptissä käytettiin aiemmin mm. CommonJS -moduulijärjestelmää, jota käytetään erityisesti Node.js:ssä. Se käyttää require ja module.exports -avainsanoja moduulien tuontiin ja vientiin. CommonJS kehitettiin vuonna 2009. Projekti aloitettiin Mozilla-insinööri Kevin Dangoorin toimesta ja se tunnettiin alun perin nimellä ServerJS. Elokuussa 2009 projekti nimettiin uudelleen CommonJS:ksi. CommonJS:n tavoitteena oli standardoida JavaScriptin moduuliekosysteemi erityisesti palvelinpuolen JavaScriptille, mutta sitä käytetään myös selainpuolella vaikka selainympäristöissä koodi täytyy yleensä pakata transpilointityökalujen avulla.
Esimerkkejä:
CommonJS
Tiedosto: math.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
module.exports = {
add,
subtract
};
Tiedosto: main.js
const math = require('./math');
console.log(math.add(2, 3)); // 5
console.log(math.subtract(5, 2)); // 3
ES6 Modules
Tiedosto: math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
Tiedosto: main.js
import { add, subtract } from './math.js';
console.log(add(2, 3)); // 5
console.log(subtract(5, 2)); // 3
Destrukturointi (destructuring)
Helpottaa taulukoiden ja olioiden arvojen purkamista muuttujiksi. Esimerkki:
const user = {
username: 'johndoe',
email: 'john@example.com',
location: {
city: 'Helsinki',
country: 'Finland'
}
};
// Purkaminen muuttujiksi
const { username, email, location: { city, country } } = user;
console.log(username); // "johndoe"
console.log(email); // "john@example.com"
console.log(city); // "Helsinki"
console.log(country); // "Finland"
Spread ja rest -operaattorit
Nämä operaattorit tehostavat taulukoiden ja objektien käsittelyä. Spread-operaattori levittää taulukon tai olion arvot, kun taas rest-operaattori kerää useita arvoja yhteen taulukkoon.
Spread-operaattori
Spread-operaattoria (...) käytetään taulukoiden ja olioiden arvojen levittämiseen. Se on hyödyllinen esimerkiksi taulukoiden yhdistämisessä ja olioiden kopioinnissa.
Taulukon yhdistäminen
const fruits = ['apple', 'banana'];
const moreFruits = ['cherry', 'date'];
const allFruits = [...fruits, ...moreFruits];
console.log(allFruits); // ["apple", "banana", "cherry", "date"]
Olion kopioiminen ja yhdistäminen
const user = {
username: 'johndoe',
email: 'john@example.com'
};
const additionalInfo = {
age: 30,
location: 'Helsinki'
};
const userProfile = { ...user, ...additionalInfo };
console.log(userProfile);
// { username: "johndoe", email: "john@example.com", age: 30, location: "Helsinki" }
Rest-operaattori
Rest-operaattoria (...) käytetään funktioiden parametreissa keräämään useita argumentteja yhteen taulukkoon. Se on hyödyllinen esimerkiksi silloin, kun halutaan käsitellä muuttuva määrä argumentteja.
Funktioiden parametrit
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(4, 5, 6, 7)); // 22
Taulukon destrukturointi
const [first, second, ...rest] = [10, 20, 30, 40, 50];
console.log(first); // 10
console.log(second); // 20
console.log(rest); // [30, 40, 50]
Template Literals
Template literals tarjoaa kätevän tavan työskennellä merkkijonojen (string) kanssa. Ne mahdollistavat monirivisten merkkijonojen ja muuttujien käytön merkkijonon sisällä ilman monimutkaista syntaksia.
const name = 'John';
const greeting = `Hello, my name is ${name}.`;
console.log(greeting); // "Hello, my name is John."
Oletusparametrit (Default Parameters)
Default parameters mahdollistavat oletusarvojen määrittämisen funktioiden parametreille.
function greet(name = 'Guest') {
return `Hello, ${name}!`;
}
console.log(greet()); // "Hello, Guest!"
console.log(greet('John')); // "Hello, John!"
Enhanced Object Literals
ES6 paransi objektien kirjaimellista syntaksia, mikä tekee objektien määrittelystä selkeämpää ja tiiviimpää.
const name = 'John';
const age = 30;
const person = {
name,
age,
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
};
person.greet(); // "Hello, my name is John."
Map ja Set
Map ja Set ovat tietorakenteita, jotka tarjoavat tehokkaat tavat tallentaa ja käsitellä tietoja.
const map = new Map();
map.set('key', 'value');
console.log(map.get('key')); // "value"
const set = new Set([1, 2, 3, 3]);
console.log(set.has(2)); // true
console.log(set.size); // 3 (duplikaatit poistetaan)
Yhteenveto
Kävimme tässä artikkelissa läpi ES6:n tärkeimpiä ominaisuuksia, jotka ovat vielä tänäänkin oleellisessa osassa Javascript-ohjelmoinnissa. Päivityksiä on tullut sen jälkeenkin, mutta ES6 päivitys jäi legendaariseen asemaan kattavan sisältönsä vuoksi.
Jälkikirjoitus (async/await)
Ehkä yksi maininta on tarpeen tehdä yllä olevien osuuksien osalta: lupaukset (Promises) on edelleen yksi tapa käsitellä asynkronista ohjelmakoodia, mutta ECMAScript 2017 toi vuonna 2017 uuden tavan: async / await. Se perustuu lupauksiin (promises), mutta mahdollistaa asynkronisen koodin kirjoittamisen synkronisen koodin tapaan.
await-avainsana: Tätä käytetään async-funktion sisällä odottamaan lupauksen täyttymistä. await-avainsana pysäyttää funktion suorituksen, kunnes lupaus täyttyy.
async-avainsana: Tätä käytetään funktioiden määrittelyssä, jotka palauttavat lupauksen. async-funktio palauttaa aina lupauksen.
Esimerkki:
const fetchUserData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
const user = await response.json();
console.log(user);
} catch (error) {
console.error('Error fetching user data:', error);
}
};
// Kutsutaan funktiota ilman await-avainsanaa
fetchUserData();
Lisätietoja ES6:n sisällöstä
Lisätietoja ES6 sisällöstä voi katsoa esim. osoitteesta: