ES6 ile Gelen Yenilikler

Emre Acar
Kodcular

--

ES6'dan once, bir değişkeni tanımlamanın tek yolu var anahtar kelimesiydi. Artık gelişmiş işlevsellik sağlayan birkaç farklı seçeneğimiz var.

const

const kelimesi constant kelimesinden gelir ve sabit anlamını taşımaktadır. Kısaca const, değiştirilemeyen bir değişkendir. JavaScript, ES6'da sabitleri tanıttı. const’lardan önce, sadece üzerine yazılabilen değişkenler vardı.

var user = true
user = false
console.log(user) // false

Sabit bir değişkenin değerini sıfırlayamayız, eğer değerin üzerine yazmaya çalışırsak, bir konsol hatası alırız.

const user = true
user = false
Bir sabitin üzerine yazma denemesi

let

let ile tanımlanan değişkenler sonradan değiştirilebilir ancak bir kez tanımlanabilir.

let login = true;
console.log(login); // true
...
login = false;
console.log(login); // false

tekrar tanımlamaya çalışırsanız hata meydana gelecektir.

let user = "Emre";
...
var user = "Acar";

JavaScript’te curly bracket (kıvrımlı parantez { } ) ile kod blokları oluşturuyoruz. Fonksiyonlar ve curly bracket ile oluşturulan bloklar değişkenlerin kapsamını engellerler.

for(let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
console.log(i); // undefined

Herhangi bir kod bloğunun içerisinde let kullanmak global değişkenin değerini korur:

var title = "JavaScript"if (title) {
let title = "React"
console.log('block', title) // React
}
console.log('global', title) // JavaScript

Templete String

Templete string’ler bize dize birleştirme işlemine bir alternatif sunuyorlar. Ayrıca dizeler içerisine değişkenler eklememize izin veriyorlar.

Geleneksel dize birleştirme işlemi

console.log("Adım:" + firstName + " Soyadım: " + lastName)

Artık bir dize oluştururken değişkenleri ${} ile çevreleyerek ekleyebiliriz.

console.log(`Adım: ${fistName} Soyadım: ${lastName}`)

Bu özellik çok daha büyük yazılar içerisinde değişkenleri kullanmamız gerektiğinde işimizi çok kolaylaştırıyor ve daha anlaşılır olmasını sağlıyor.

document.body.innerHTML = `
<section>
<header>
<h1>The HTML5 Blog</h1>
</header>
<article>
<h2>${article.title}</h2>
${article.body}
</article>
<footer>
<p>copyright ${new Date().getYear()} | The HTML5 Blog</p>
</footer>
</section>
`

Varsayılan Parametreler

Fonksiyonlara gönderilen argümanlara değer atanmadığında varsayılan değer kullanılacaktır.

function getUser(name="Emre Acar", permit="leave"){
console.log(`${name} is ${permit}`)
}

getUser fonksiyonuna argüman verilmese dahi, varsayılan değerler kullanılarak doğru şekilde çalışacaktır.

Arrow Function

function anahtar sözcüğü kullanmadan fonksiyon oluşturabiliriz. Ayrıca return anahtar sözcüğünü de kullanmamız gerekmez.

var person = function(firstname){
return `${firstname} of Ankara`
}
// arrow function
var person = firstname => `${firstname} of Ankara`

Artık bir satırda tanımladığımı bir fonksiyonumuz var. Dikkat ettiyseniz fonksiyon anahtar sözcüğü kaldırıldı, => işareti neyin return olması gerektiğini söylüyor son olarak eğer fonksiyon tek bir argüman alırsa ( ) işaretlerini kaldırabiliriz.

var user = (firstName, lastName) => `${firstName}, ${lastName}`

Birden fazla satır var ise curly bracket kullanmak gerekir.

var user = (firstName, lastName) => {
if (!firstName) {
throw New Error('A firstName is required')
}
if (!lastName) {
throw New Error('A lastName is required')
}
return `${fistName}, ${lastName}`
}

Şimdi size çok ilginç bir örnek göstereceğim. Bu örneğe dikkat edin.

var cars = {
models: ["BMW", "Mercedes", "Renault", "Peugeot", "Citröen"],
print: function(delay=1000){
setTimeout(function() {
console.log(this.models.join(","))
}, delay)
}
}
cars.print() // Cannot read property 'join' of undefined

Bu fonksiyonu çalıştırdığınızda hata alacaksınız, çünkü .join yöntemini this üzerinde kullanmaya çalışıyor. Bu durumda this, window nesnesidir. Alternatif olarak this’in kapsamını korumak için arrow function sözdizimini kullanabilirsiniz.

var cars = {
models: ["BMW", "Mercedes", "Renault", "Peugeot", "Citröen"],
print: function(delay=1000){
setTimeout(() => {
console.log(this.models.join(","))
}, delay)
}
}
cars.print() // BMW, Mercedes, Renault, Peugeot, Citröen

Yukarıdaki gibi setTimeout içerisinde arrow function kullanılırsa this.model kullanarak model’e ulaşılabilinir. Dikkatli olun, her zaman scope’u aklınızda tuttuğunuza dikkat edin. Arrow fonksiyon, this’in kapsamını engellemez.

Not: Daha iyi anlamanız için javaScript deki this kavramını araştımanız gerekebilir.

Destructuring Assignment

Dizilerden veya nesnelerden gelen özellikleri farklı değişkenlere açılmasını mümkün kılan bir JavaScript ifadesidir.

var cities = {
ankara: "çankaya",
bursa: "inegöl",
izmir: "bornova",
istanbul: ["adalar", "beşiktaş", "beyoğlu", "maltepe", "üsküdar"]
}
var {ankara, izmir} = cities
console.log(ankara, izmir) // çankaya bornova

Kod, ankara ve izmiri nesneden çıkarır ve onlar için yerel değişkenler yaratır. Ayrıca ankara ve izmir değişkenleri değiştirilebilir.

var {ankara, izmir} = cities
ankara = "mamak"
izmir = "buca"
console.log(ankara) // mamak
console.log(izmir) // buca
console.log(cities.ankara, cities.izmir) // çankaya bornova

Fonksiyon argümanına {} ile belirterek sadece o değeri de alabiliriz.

var user = ({firstName}) => {
console.log(`$firstName` of Ankara)
}
var regularPerson = {
firstName: "Mustafa",
lastName: "Yılmaz"
}
user(regularPerson) // Mustafa of Ankara

firstName’i imha ederek, yalnızca firstName değişkenini kullanacağımızı beyan ederiz.

Değerler ayrıca dizilerden de yok edilebilir. Bir dizinin ilk değerini bir değişken ismine atamak istediğimizi düşünün.

var [firstResort] = ["elma", "armut", "kira"]
console.log(firstResort) // elma

Ayrıca gereksiz değerleri virgül kullanarak liste eşleştirmesiyle iletebiliriz. Liste eşleştirme, virgüllerin atlanması gereken öğelerin yerini aldığında gerçekleşir. Aynı diziyle, ilk iki değeri virgüllerle değiştirerek son değere erişebiliriz.

var [,,thirdResort] = ["elma", "armut", "kiraz"]
console.log(thirdResort) // kiraz

Object Literal Enhancement

Object literal enhancement, destructuring assignment tam tersidir. Yeniden yapılanma ya da bir araya getirme sürecidir. Değişkenleri global kapsamdan alıp bir nesneye çevirebiliriz.

var name = "Tahta"
var elevation = 4839
var funCase = {name, elevation}console.log(funPer) // {name: "Emre", elevation: 4839}

Nesne yöntemlerini tanımlarken artık function anahtar sözcüğünü kullanmak gerekmez

// Eski
var user = {
name: name,
lastName: lastName,
fullName: function(){
var name = this.name.toUpperCase() + this.lastName.toUpperCase()
console.log($name)
}
}
// Yeni
const user = {
name,
lastName,
fullName(){
var name = this.name.toUpperCase() + this.lastName.toUpperCase()
console.log($name)
}
}

Spread Operatörü

Spread operatörü, birkaç farklı görevi yerine getirir. İlk olarak yayma operatörü dizilerin içeriğini birleştirmemize izin verir. Örneğin iki dizimiz olsaydı, iki diziyi bir araya getiren üçüncü bir dizi yapabilirdik.

var meyveler = ["Karpuz", "Kiraz", "Muz"]
var sebzeler = ["Havuç", "Salatalık"]
var buzdolabi = [...meyveler, ...sebzeler]console.log(buzdolabi.join(', ')) // Karpuz, Kiraz, Muz, Havuç, Salatalık

Şimdi bir diziyi tersine çevirip ilk elemanını almak istersek.

var meyveler = ["Karpuz", "Kiraz", "Muz"]
var [son] = meyveler.reverse()
console.log(son) // Muz
console.log(meyveler.join(', ')) // Muz, Kiraz, Karpuz

Yukarıdaki örnekte ne olduğuna dikkat edin. reverse işlevi aslında orjinal diziyi değiştirdi. Spread operatörünü kullanarak orijinal diziyi değiştirmemize gerek yoktur; dizinin bir kopyasını oluşturabilir ve sonra tersine çevirebiliriz.

var meyveler = ["Karpuz", "Kiraz", "Muz"]
var [son] = [...meyveler].reverse()
console.log(son) // Muz
console.log(meyveler.join(', ')) // Karpuz, Kiraz, Muz

Spread operatörü, dizideki öğelerin bir kısmını veya kalanını almak için de kullanılabilir.

var meyveler = ["Karpuz", "Kiraz", "Muz", "Elma", "Limon"]
var [ilk, ...rest] = meyveler
console.log(rest.join(", ")) // Kiraz, Muz, Elma, Limon

Spread operatörünü, fonsiyon argümanlarını bir dizi olarak toplamak için de kullanabiliriz. Burada spread operatörünü kullanarak n sayısı argümanını alan ve bazı konsol mesajlarını yazdırmak için bu argümanları kullanan bir fonksiyon tanımlıyoruz.

function tellMe(...args){
var [start, ...remaining] = args
var [finish, ...stops] = remaining.reverse()
console.log(`drive through ${args.length} towns`)
console.log(`start in ${start}`)
console.log(`the destination is ${finish}`)
console.log(`stopping ${stops.length} times in between`)
}
tellMe(
"Ankara",
"İstanbul",
"İzmir",
"Manisa",
"Bursa"
)

Spread operatörü ayrıca nesneler için de kullanılabilir. Spread operatörü nesnelerle kullanmak, dizilerle kullanmaya benzer.

var computer = {
cpu: "i5 1.6GHz",
ram: "8 GB DDR"
}
var disk = "320 GB SSD"
var clientComputer = {
...computer,
disk
}
console.log(clientComputer)
// {cpu: "i5 1.6GHz", ram: "8 GB DDR", disk: "320 GB SSD"}

Promise

Promise bize eşzamanlı olmayan davranışlardan bir anlam çıkarmanın yolunu gösterir. Eşzamansız bir istek yaparken, iki şeyden biri olabilir: her şey umduğumuz gibi gider veya bir hata oluşur.

Aşağıdaki örnekte, getFakeMembers fonksiyonu yeni bir promise döndürür. Promise, API’ye bir istekte bulunur. Eğer promise başarılı olursa, veriler yüklenecektir. Eğer promise başarısız olursa, bir hata meydana gelecektir:

const getFakeMembers = count => new Promise((resolves, rejects) => {
const api = `https://api.randomuser.me/?nat=TR&results=${count}`
const request = new XMLHttpRequest()
request.open('GET', api)
request.onload = () =>
(request.status === 200) ?
resolves(JSON.parse(request.response).results) :
reject(Error(request.statusText))
request.onerror = (err) => rejects(err)
request.send()
})

Yukarıda promise oluşturuldu, ancak henüz kullanılmadı. Promise öğesini getFakeMembers işlevini çağırarak ve yüklenmesi gereken üye sayısını girerek kullabiliriz. function, promise yerine getirildikten sonra bir şeyler yapmak için zincirlenebilir. Buna komposizyon denir. Ayrıca hataları işleyen ek bir geri bildirim (callback) kullanacağız.

getFakeMembers(5).then(
members => console.log(members),
err => console.error(
new Error("Cannot load members"))
)

Class’lar

Daha önce JavaScript’te class yoktu. Tipler fonksiyonlarla tanımlanırdı. Şimdi bir örnekle fonksiyon yaratalım ve prototype kullanarak fonksiyon nesnesindeki yöntemleri tanımlayalım.

function Tatil(hedef, sure) {
this.hedef = hedef
this.sure = sure
}
Tatil.prototype.yazdir = function() {
console.log(this.hedef + " | " + this.sure + " gün")
}
var antalya = new Tatil("Antalya", 7);
antalya.yazdir();

Klasik nesne oryantasyonuna alışkınsan, bu muhtemelen hoşuna gitmeyecektir.

ES6 class tanımlamasına izin verir ancak JavaScript hala aynı şekilde çalışır. Fonksiyonlar nesnedir ve kalıtım prototype ile ele alınır, ancak klasik nesne yönelmesinden geliyorsanız bu sözdizimi daha anlamlı olur:

class Tatil {
constructor(hedef, sure) {
this.hedef = hedef
this.sure = sure
}
yazdir() {
console.log(`${this.hedef}'a ulaşım ${this.sure} gün sürer.`)
}
}
var antalya = new Tatil("antalya", 7)
antalya.yazdir() // antalya'a ulaşım 7 gün sürer.

Modüller

Bir JavaScript modülü, diğer JavaScript dosyalarına kolayca dahil edilebilen ve yeniden kullanabilen bir kod parçasıdır. Yakın zaman kadar, modüler JavaScript ile çalışmanın tek yolu, modül alma ve verme işlemlerini yapabilen bir kütüphane kullanmaktı. ES6 ile JavaScript artık modülleri desteklemektedir.

text-helper.js

export const print(message) => log(message, new Date())
export const log(message, timestamp) =>
console.log(`${timestamp.toString()}: ${message}`)

export, başka bir modülde kullanılacak olan herhangi bir JavaScript türünü export yapmak için kullanılabilir. Bu örnekte, yazdırma işlevi ve log işlevi dışa aktarılıyor.

Bazen bir modülden yalnızca bir değişkeni dışa aktarmak isteyebilirsiniz. Bu durumlarda export default kullanabilirsiniz

mt-freel.js

const freel = new Expedition("Mt. Freel", 2, ["water", "snack"])
export default freel

Modüller, import ifadesi kullanılarak diğer JavaScript dosyalarında kullanılabilir. Birden fazla dışa aktarma içeren modüller, object destructuring yapılarak tanımlanabilinir.

import { print, log } from './text-helpers'
import freel from './mt-freel'
print('printing a message')
log('logging a message')
freel.print()

Modül değişkenlerini yerel olarak farklı değişken isimleri altında tanımlayabilirsiniz:

import { print as p, log as l } from './text-helpers'p('printing a message')
l('logging a message')

Ayrıca * ile her şeyi tek bir değişkene de aktarabilirsiniz:

import * as fns from './text-helpers

ES6 ile gelen tüm farklılıkları dilim döndüğünce sizlere aktarmaya çalıştım. Umarım sizin için yararlı olmuştur.

Sonraki:

Giriş ve Tanımlamalar (JS Fonksiyonel Programlama 1)

Imperative vs Declarative (JS Fonksiyonel Programlama 2)

--

--