co-wprowadziło-es8-do-js

Co wprowadziło ES8 do JS

Podziel się ze znajomymi

To kolejny wpis o zmianach jakie zostały wprowadzone na przestrzeni ostatnich lat w JavaScript. W tym artykule przyjrzymy się bliżej zmianom wprowadzonym w 2017 roku. Jeżeli chcecie zapoznać się ze zmianami wprowadzonymi przed 2017 rokiem, to zachęcam Was do przeczytania moich wpisów:

Object.values/Object.entries

Podobnie jak Object.keys zwracają tablice, której kolejność jest zgodna z kolejnością Object.keys. Każda pozycja w tablicy zawiera odpowiednio klucz i wartość atrybutu iterowanego obiektu.

Przed ES8 programiści chcący iterować po utworzonym obiekcie, musieli używać Object.keys i iterować po zwróconej tablicy. Zmuszeni byli do korzystania z zapisu obj[key], aby uzyskać wartość danego elementu. Poniżej znajduję się przykład

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
Object.keys(person).forEach(key=>{
  console.log(`${key}: ${person[key]}`)
})

Mogli także wykorzystać do tego celu pętlę for of.

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
for (let key of Object.keys(person)) {
  console.log(`${key}: ${person[key]}`)
}

Poza tymi dwoma metodami, programiści mogli jeszcze wykorzystać pętlę for in. Pętla ta iteruje po wszystkich właściwościach, np. prototype, a nie tylko tych, które utworzył programista. Może to powodować pewne błędy w działaniu.

Object.values zwraca tablicę wartości, po której można iterować za pomocą forEach lub za pomocą pętli for/of.

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
Object.values(person).forEach(value=>console.log(value))

for (let value of Object.values(person)) {
  console.log(value)
}

Object.entries zwraca tablicę, której elementy to tablice zawierające w sobie pary klucz, wartość. W rezultacie możemy iterować za równo za pomocą forEach jak również for/of. Poniżej kod pokazujący jak wygląda zwracana struktura.

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
console.log(JSON.stringify(Object.entries(person)))

Poniżej przykładowy kod z wykorzystaniem forEach oraz for/of

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
Object.entries(person).forEach(([key, value]) => {
console.log(`${key}: ${value}`)
})

for (let [key, value] of Object.entries(person)) {
  console.log(`${key}: ${value}`)
}

Iterowanie po obiekcie jest teraz jeszcze łatwiejsze. Programiści mają do dyspozycji dwie dodatkowe metody, które robią to w podobny sposób jak Object.keys. Ważne jest aby pamiętać o podobieństwach:

  • Iterowanie wyłącznie po własnych właściwościach, pomijane są właściwości takie jak prototype,
  • Taka sama kolejność elementów.

String padding

Dodane zostały dwie metody: padStart() oraz padEnd(). Obie metody zwracają ciąg o określonej długości, uzupełniając brakujące znaki wskazanym tekstem. Metody te przyjmują dwa parametry. Pierwszy parametr odpowiada za długość zwracanego stringa. Drugi parametr określa jakim tekstem będą wypełniane brakujące znaki. W przypadku nie podania drugiego parametru, brakujące znaki zostaną wypełnione spacjami. Przykładowy kod:

const string = 'code'.padStart(10)
const string2 = 'code'.padStart(10, ':)')
console.log(`${string} - ${string.length}`)
console.log(`${string2} - ${string2.length}`)

Różnica pomiędzy tymi metodami polega na tym, że padStart dodaje określony tekst przed głównym stringiem, a metoda padEnd za głównym stringiem.

const string = 'code'.padStart(10)
const string2 = 'code'.padStart(10, ':)')
const string3 = 'code'.padEnd(10)
const string4 = 'code'.padEnd(10, ':)')
console.log(`${string} - ${string.length}`)
console.log(`${string2} - ${string2.length}`)
console.log(`${string3} - ${string3.length}`)
console.log(`${string4} - ${string4.length}`)

Object.getOwnPropertyDescriptors

Metoda ta zwraca własne deskryptory właściwości obiektu. Przyjmuje jeden parametr, który odpowiada za przekazanie obiektu, z którego mają zostać pobrane deskryptory. Warto zapamiętać, że zwraca wszystkie własne deskryptory obiektu w przeciwieństwie do metody Object.getOwnPropertyDescriptor, która odpowiada za zwrócenie wybranego deskryptora.  W przypadku braku własnych właściwości, zwracany jest pusty obiekt. Struktura zwracana przez metodę:

value – wartość danego atrybutu

writable – jeśli zwraca true, to wartość może być zmieniona

get – funkcja, która służy jako getter 

set – funkcja która służy jako setter

configurable – zwraca true, jeżeli typ może zostać zmieniony oraz właściwość może zostać usunięta z obiektu,

enumerable – zwraca true, jeżeli właściwości będzie dostępna podczas iteracji po właściwościach obiektu.

const person = {firstName: 'Adam', lastName: 'Kowalski', age: 30}
const descriptors = Object.getOwnPropertyDescriptors(person);
console.log(descriptors);
console.log(descriptors.firstName);

Trailing commas in function parameter lists and calls

Twórcy standardu postanowili ujednolicić zapis przecinków podczas deklaracji funkcji z zapisem tablic oraz obiektów literałowych. Przed ES2017 poprawnie utworzona funkcja wyglądała tak jak poniżej:

const print = function(a,
  b,
  c,
  d) {
  console.log(a, b, c, d)
}
print(1, 2, 3, 4)

Od standardu ES8 dobrą praktyką jest dodawanie przecinka na końcu

const print = function(a,
  b,
  c,
  d,
) {
  console.log(a, b, c, d)
}
print(1, 2, 3, 4)

Dzięki temu JS toleruje przecinki po ostatnim elemencie tablicy, po ostatniej wartości obiektu literałowego oraz po ostatnim argumencie deklarowanej funkcji. Poniżej przedstawiam przykład pokazujący omawiającą spójność zapisów.

const person = {
  firstName: 'Adam',
  lastName: 'Kowalski',
  age: 30,
}
const fruits = [
  'apple',
  'bannana',
]
const print = function(a,
  b,
  c,
  d,
) {
  console.log(a, b, c, d)
}
print(person, fruits, 1, 2)

Async Functions

Jedną z największych zmian w ES8 było wprowadzenie funkcji asynchronicznych. We wcześniejszych wersjach JS w celu utworzenia funkcji asynchronicznej wykorzystywano bezpośrednio obiekt Promise, który został wprowadzony w ES6. Poniżej znajduję się przykład.

fetch('https://jsonplaceholder.typicode.com/todos')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error))

Dzięki wprowadzeniu funkcji async/await możemy teraz powyższą funkcję zapisać zdecydowanie prościej. Poniżej przykład wykorzystania funkcji asynchronicznych.

async function fetchData () {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos')
    const data = response.json()
    console.log(data)
  } catch(error) {
    console.error(error)
  }
}

Funkcję asynchroniczne mogą, ale nie muszą oczekiwać na asynchroniczne operacje oparte na obietnicach. W efekcie taka funkcja zawsze zwraca obietnice, którą można obsłużyć za pomocą metod then, catch. Funkcje asynchroniczne pisane dzięki async/await wizualnie wyglądają jak kod synchroniczny i wykonywane są od góry do dołu. Zdecydowanie ułatwia to czytanie i rozumienie kodu, który wykonuje się podczas działania funkcji. Poniżej przykład z obsługą funkcji asynchronicznej za pomocą metody then().

async function fetchData () {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos')
    const data = response.json()
    console.log(data)
    return data
  } catch(error) {
    console.error(error)
  }
}
fetchData().then(response => console.log(response))

Podsumowanie

ES2017 wprowadził kilka ciekawych rozwiązań. Najpopularniejszą nowością są funkcje asynchroniczne, które zdecydowanie poprawiają czytelność kodu asynchronicznego. Ustandaryzowanie przecinków, również pozytywnie wpływa na pracę z kodem, ponieważ nie trzeba się już zastanawiać czy pisząc deklarację funkcji można za ostatnim argumentem postawić przecinek czy też nie. Nowe iteratory obiektowe, pozwalają na wygodniejszą pracę podczas iterowania po właściwościach własnych obiektów. Wszystkie zmiany wprowadzone w 2017 roku pozytywnie wpływają na pracę z kodem oraz dają nowe możliwości programistom.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *