Photo by Erik-Jan Leusink on Unsplash

KISACA JS

2020 yılında ES11 ile JavaScript Diline Gelen Yeni Özellikler

JavaScript tarihçesi ile ilgili blog yazımı güncellerken ES11, ES12, ES13 ait JavaScript gelişmeleri anlatmadığımı farkettim. Bu blog ES11 gelen yeni özellikleri analiz edeceğiz

Onur Dayıbaşı
Frontend Development With JS
7 min readFeb 5, 2023

--

ES11 2020 yılında JavaScript diline getirilen

  • Optional Chaining (?)
  • Nullish Coalescing (??)
  • BigInt (n)
  • Dynamic Import
  • Private Fields (#)
  • Static Fields
  • MatchAll
  • globalThis
  • Promise.allSettled

1. Optional Chaining (?)

JS geliştiricileri genelde bu tip türde “TypeError: Cannot read property” bir hata ile sıkça karşılaşır. Bir objenin içerisinde property erişimi sırasında objenin de olmayışı bu tip hatalara neden olur. Burada ilk önce o objenin null check yapılması ve bir if içerisinde bu tip değerlendirmelerin yapılması gerekir.

Bu da kodun bir çok yerinde ekstra if kontrolü gereksinimi doğurur. (Not: TypeScript gibi dillerin ortaya çıkması ve geliştiricileri ekstra if checklerinden korumasıda bir yöntemdir. Fakat JS kendi işini kolaylaştırıcı Optional Chaining özelliğini getirmiştir.

Aşağıdaki örnekte görüleceği gibi olmayan bir nesnenin bir özelliğini ulaşmak istediğimizde TypeError alırız.

const person= {
bag: {
orange: "2kg"
banana: "1kg"
}

}

console.log(person.bag.orange) // output is: ‘2k’
console.log(person.bag.patato) // output is: 'undefined'

console.log(person.wallet.coin)
// TypeError: Cannot read property 'coin' of undefined

Optional Chaining bunu önlemek için ? yöntemi getirmiştir.

console.log(person.wallet?.coin) // output is: undefined

Aynı kontrollü çağrımı array ve fonksiyon çağrımlarında da kullanabiliriz.

console.log(userList?.[1]) //Array item access
console.log(getWords?.()) //Function acess

2. Nullish Coalescing (??)

Normal’de biz falsy durum olduğunda bize OR operatörünün diğer tarafını veriyordu.

const format = (value) => {
const defaulted = value || 'default';
return `I formatted ${defaulted} for you.`;
};

Tüm falsy durumla değil de sadece undefined ve null durumunda diğer kısmı ele alacak yeni bir operatör olan ?? işareti (false, 0 “”) durumlarında değilde sadece undefined ve null da çalışmasıdır.

const format = (value) => {
const defaulted = value ?? 'default';
return `I formatted ${defaulted} for you.`;
};

Çünkü yeri geldiğinde left-side(sol tarafta) yer alan 0, 0n, false, “” gibi kavramlar bizim uygulamamız izin anlamlı olabilir. Bu durumda ?? kullanabilirsiniz.

Eksta Not : Falsy değerler nelerdir?

İlk önce “Falsy” kavramını anlatarak başlamak istiyorum. Boolean kapsamda değeri False olan değişkenlere “falsy” diyoruz. Bunlar if(){}, while(){}, vb durum karşılaştırmalarında ilgili kod bloklarının içerisine girmemesini sağlayarak mantıksal akışlar oluşturmasını sağlar.

Javascipt içerisinde 7 tip falsy değer bulunmaktadır. Aşağıdaki tüm değerler JS tarafından false olarak algılanır.

  • false : boolean değer olarak
  • 0 : int değer olarak
  • 0n: BigInt değeri olarak
  • "", '', `` : Boş string değerleri. Double quotes, Single quotes ve String template literals
  • null: Bir değişkenin değeri yok şeklinde bir atama belirtilmiş ise.let a=null
  • undefined: Bir değişken tanımlanırken hiç bir atama yapılmamış ise let a;
  • NaN: Not a Number

Ama bu falsy değerlerin uygulamamız içerisinde bir anlamı olabilir. Sadece

3. BigInt (..n)

JavaScript 2⁵³ — 1 is the maximum number you can represent in JavaScript. Number.MAX_SAFE_INTEGER değer olarak kullanılır. Bu da 9007199254740991 değeri yapıyor. Integer üzerinden işlemler yaptığınızda 2 eklediğinizde , 4 eklediğinizde artık yanlış değerler verdiğini görebilirsiniz. Artık bu rakam üzerinde güvenilir işlemler yapabilmeniz mümkün değildir.

Artık rakamların sonuna n karakteri ekleyerek veya number çevresini BigInt(number) üzerinden kullanarak işlemlerinizi büyük sayılar ile de güvenli bir şekilde yapabilir hale geldiniz.

Integer ve BigInt kullanımı

4. Dynamic import

Import / Export konusunun gelişimini konusunda daha öncesinden yazmış olduğum bu 2 blog yazısını okumanızı öneririm.

Sonuç itibari ile Modern JavaScript’de import işlemlerini JavaScript paketinin en üstünde statik bir şekilde yapabiliyordunuz.

Export / Import codes

Aslında bu kodun daha güvenilir olması ve daha az kırılgan olması açısından oldukça faydalıdır. Ama Web’de bir çok kodu uygulamanın ilk başından değil kullandıkça gereksinimiz doğar.

Bu durumda da bazı kodların uygulamanıza sonradan dahil edilebilmesi hem esnek bir mimari hemde performans açısından gerekli olabilir.

import ... from  'msg'   // diyebilirsiniz fakat module en başında statik

//Aşağıdaki şekilde kullanıma izin verilmez

if() import ... from 'msg' //Condition
{import ... from 'msg'} //Blok icerisinde

Yani bizim kodun içerisinde bir düğmeye bağlı, bir condition bağlı import yapmamıza izin vermez. Fakat Dynamic Import yöntem ile Runtime modülü import edip kullanabilmenize olanak sağlar.


import("/msg").then(({hello, world}) => {
hello();
world();
});

//Veya..

let {hello, world} = await import('./msg');
hello();
world();

import.meta

Dynamic import ek olarak , halihazırda içe aktarılan modülün bilgilerini içeren bir meta özniteliği de sağlar. Şu anda içinde, modülün başvuruda bulunduğu URL’yi temsil eden bir url özelliği bulunmaktadır.

5. Private Fields (#)

CSS Tricks (Implementing Private Variables In JavaScript) blog yazısı bu konuyu detaylıca anlatılmış.

IIFE

2015 öncesi bu değişkenlerin (var) fonksiyonların her yerden erişebilmesi bir problemdi. Bunun için IIFE fonksiyonları kullanılırdı

// Define "a" in global scope
var a = 123;

// Define "b" in function scope
(function() {
console.log(b); //=> Returns "undefined" instead of an error due to hoisting.
var b = 456;
})();

console.log(a); // => 123
console.log(b); // Throws "Ref

Bunun için Eğer bir fonksiyon hemen çağrılıp oluşturulan sonuç/sonuç objesi bir değişkende saklanıyorsa bu tip fonksiyonlara IIFE (Immediately invoked function expression) deniyor. Bu tip fonksiyonların amacı genelde bu scope içerisinde oluşan değişkenlerin sadece o kapsam(scope) erişilebilir olmasını sağlıyor. Genelde JQuery, Prototype gibi kütüphanelerde değişken isimlerinin çakışmaması ve scope içerisinde işlemlerin yapılabilmesi için IIFE yöntemi kullanılmıştır.

Let, Const

ES6 variables değişkenleri ile birlikte let,const ile birlikte artık blog seviyesinde değişkenler tanımlayabilmeye başladıkç Neden? var → let, const

Fonksiyon module pattern yapısı ile private ve public property yapıları oluşturabilir hale geldik.

https://css-tricks.com/implementing-private-variables-in-javascript/

ES6 Classes

ES6 Classes ile Constructor içerisinde değişkenlerinizi oluşturabildiğiniz variable oluşturup bunların sınıfın fonksiyonları içerisinden kullanabilir hale geldik fakat bunlar halen dışarıdan erişebilirliği tamamen kaldırmayı sağlamadı. Bütün private değişkenler belli olsun diye _ ile tanımlamalar yapıldı, tabi bu yapı dışarıdan değiştirilmeye engel değil developer sadece private değişkenleri bilgilendirmek için görünürlüğü arttırıcı değişken ismi tanımlamasıydı.

Veya tam privacy sağlamak için tüm değişkenleri ve fonksiyonları constructor metodu içerisinde tanımlamak gerekiyorki bu da Class kullanımında doğru bir yaklaşım değil.

Private Fields

Yeni private field yeteneği sayesinde # sadece sınıf içerisinden erişebilecek değişkenler tanımalanız mümkün.

class User {
#name = "Onur";

getName() {
return this.#name;
}
}
const user1= new User();
console.log(user1.getName()); // Onur
console.log(user.#name) // Private field error

6. Static Fields (static)

Java dilinde bulunan özellikler yavaş yavaş JavaScript dilinin içerisine geliyor. Bunlardan bir tanesi’de static ile tanımlanmış bir fonsiyonu new ile Class oluşturmadan direk Class tanımlamasına bağımlı fonksiyonlar oluşturmamızı sağlar.

static keyword kullanımı

7. MatchAll

Regular Expression kullanırken match kelimesi bu regex geçtiği bütün kelimeleri bulurken bunlar ile ilgili indeksleri vb.. bulmaz bunun yerine sadece kelimeyi döner.. Sizin bu kelimlerin indeksleri üzerinden bir işlem yapmanız gerektiğinde ayrı mantıklar işletmeniz gerekir. Örneğin GitHub LogViewer içerisinde renklendirme yapmak istediğimiz kısımlarda (Örnek uygulama)

Renk kodlarınının bulunup bunların değiştirilmesi gerekiyordu.

calcColoring = logLine => {
const matches = logLine.match(/\x1b\[\d+m/g);
if (hasArrayElement(matches)) {
return logLine
.replace(/\x1b\[\d+m/g, '$!$')
.split('$!$')
.map((el, index) => {
const styleCode = matches[index - 1];
return (
<span key={index} style={logLineStyle[styleCode]}>
{el}
</span>
);
});
} else {
return logLine;
}
};

Yukarıda ben bu indekslere erişim için ayrıca $!$ kodları yerleştirdim..

https://onurdayibasi.dev/log-viewer-github-color-support

Bu color hangisinin hangi match eşleştiğini bilemediğimiz için bu tarz replace yöntemlerine yönelmek zorunda kalmıştım.

MatchAll ise bize her bir eşleşmenin her bir parça ile olan eşleşme nedenlerinide array içerisinde dönerek bizim uygulaman mantığını daha iyi bir şekilde işletebilmemizi sağlar.

match vs matchAll

8. globalThis

İster JS Tarayıcıda çalışsın, İster sunucu, ister local her ortamda JS Engine çalışma ortamına bir tane Global Execution Context oluşturur ve bu Global Scope içerisinden Tarayıcılar için WebAPI ye erişim imkanı sağlar. Bu ilk Global Execution Context içerisinde bir Global Object ve this nesnesi bulunur. Bunu JSEngine kendisi ilk JS çalıştırılacak ortamda ayağa kaltığı zaman yerleştirir.

Global Execution Context -1

Örneğin aşağıda Tarayıcıda çalışan JS kodları için Console this ve window Global Objeye karşılık gelir.

Tarayıcıda ve NodeJS Runtime ortamlarında Global Context farklı farklı Runtime aynı şekilde erişebilimesi için globalThis değişkeni eklenmiş

// In a browser
window == globalThis // true

// In node.js
global == globalThis // true

9.Promise.allSettled

Promise kavramını bu blog yazısında detaylı bir şekilde anlatmıştım. Promize metodlarına allSettled metodu eklenmiştir. Gerçekleşen ve gerçekleşmeyen promise hakkında detaylı bir result geriye döndürür.

Promise Metodları

Promise prototype bağlı (then, catch, finally) metodlarında then() promise zincirleri oluşturmanızı sağlayan bağlaç görevi üstlenir. catch() reject sırasında ele alınmamış hataları yakalamanızı sağlar. finally() promise en sonunda başarılı/başarısız tamamlandığında bu metod çağrılır.

Promise işleminin başarılı/başarısız tamamlanması ardından (resolve, rejected) metodları çağrılır. Promise.resolve(value) , Promise.reject(err) gibi.

Birden fazla Promise koşullarını yöneten metodlar (all, race, allSettled)

  • all: Tüm Promise başarıyla tamamlanmasını bekler.
  • race: İçlerinden en önce hangi Promise tamamlanırsa onun sonucunu alır.
  • allSettled: Tüm Promise başarılı, başarısız işletimleri bitince sonuçlarını status leri ile birlikte geriye döner.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => { resolve("success") }, 1000)});const promise4 = new Promise((resolve, reject) => {setTimeout(() =>{ reject("fail") }, 1000)});Promise.then([promise1, promise2, promise3]).
then(function(values) { console.log(values);});
//Output ->3Promise.all([promise1, promise2, promise3]).
then(function(values) { console.log(values);});
//Output ->[3,42,"success"]Promise.allSettled([promise1, promise2, promise4]).
then(function(values) { console.log(values);});
//Output ->[{value:3,status:"fullfilled"},{value:42,status:"fullfilled"},{value:"success",status:"rejected"]

Referanslar

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.

--

--