JavaScript BOM: window, location, navigator ve Zamanlayıcılar
Tarayıcı object'lerini tanıyoruz: global window, adresi okuyan location, history ile gezinme, navigator ve screen bilgileri, setTimeout ve setInterval ile zamanlayıcılar, alert, confirm ve prompt'un neden az kullanıldığı.
Sürüm notu: Bu yazıdaki kodlar ES2026 ve güncel tarayıcılar (Chrome, Edge, Firefox, Safari) içindir.
Önce Tahmin Et
Üç satırlık bir kod. Ortadaki satır bir zamanlayıcı kuruyor ve bekleme süresi olarak sıfır veriyor:
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
Konsolda hangi sırayla ne görürsün? Sıfır milisaniye "hemen" demek değil mi? Okumaya devam etmeden önce bir tahmin yap. Cevabı zamanlayıcılar bölümünde vereceğiz.
DOM ve BOM: Sahne ve Salon
Bir tiyatro düşün. Sahnedeki dekor, oyuncular ve ışıklar oyunun kendisi; DOM tam olarak bu, yani sayfanın içeriği. Ama bir de salon var: kapılar, koridorlar, perde, saat, seyircinin oturduğu koltuklar. Oyun değişse de salon aynı kalır. Tarayıcıda bu salonun karşılığı BOM, Browser Object Model.
BOM, tarayıcının sayfanın dışında kalan kısımlarıyla konuşmanı sağlayan object'lerin toplu adıdır: pencerenin kendisi, adres çubuğu, geri ve ileri düğmeleri, tarayıcının dili, ekranın boyutu. Aslında resmî bir standardın adı değil; bu object'lerin çoğu bugün HTML standardında tanımlı ve bütün güncel tarayıcılarda aynı şekilde çalışıyor. Ama birlikte anmak için bu isim hâlâ çok kullanışlı.
window: Her Şeyin Çatısı
Tarayıcıda çalışan her script'in tepesinde window object'i durur. Bugüne kadar kullandığımız document ve console da aslında onun property'leri. Bunu konsola yapıştırıp dene:
console.log(window.document === document); // true
window.console.log("This works too");
var oldWay = "with var";
let newWay = "with let";
console.log(window.oldWay); // "with var"
console.log(window.newWay); // undefined
window global object'tir. document yazdığında motor onu önce senin değişkenlerinde arar, bulamazsa window'a bakar. Bu yüzden window. önekini çoğu zaman yazmayız.
Son iki satır, daha önce var'ı neden artık kullanmadığımızı konuşurken değindiğimiz bir farkı gösteriyor. En dışta var ile tanımlanan bir değişken window'un property'si olur ve tarayıcının kendi isimleriyle çakışabilir. let ve const ise window'a eklenmez. Küçük bir not daha: ES2020 ile gelen globalThis, hangi ortamda çalışırsan çalış global object'i verir; tarayıcıda globalThis === window.
location ve history: Adres ve Geçmiş
location
location, adres çubuğundaki URL'i parça parça okumanı ve değiştirmeni sağlar. Adresin https://example.com/products?category=books&page=2#reviews olduğunu düşün:
location.href; // "https://example.com/products?category=books&page=2#reviews"
location.protocol; // "https:"
location.hostname; // "example.com"
location.pathname; // "/products"
location.search; // "?category=books&page=2"
location.hash; // "#reviews"
Herhangi bir sitede bu satırları konsola yazıp o sayfanın adresini parçalarına ayır. search, soru işaretinden sonraki sorgu kısmını ham bir string olarak verir. İçinden category'nin değerini rahatça çekmeyi sağlayan URLSearchParams'ı Orta seride detaylandıracağız.
location sadece okumak için değil:
location.href = "https://developer.mozilla.org"; // o adrese gider
location.reload(); // sayfayı yeniler
location.replace("https://developer.mozilla.org"); // gider ama geçmişe kayıt bırakmaz
href'e yeni bir adres atamak, kullanıcının bir linke tıklaması gibidir: tarayıcı oraya gider ve geri düğmesi eski sayfaya döner. replace ise mevcut sayfanın yerine geçer; geri düğmesi bu sayfayı atlar. Bir giriş sayfasından sonra kullanıcıyı ana sayfaya yönlendirirken genellikle istediğin budur.
history
history tarayıcının o sekmedeki geçmişini temsil eder. Kendi butonlarınla geri ve ileri düğmelerinin işini yapabilirsin:
history.back(); // bir sayfa geri
history.forward(); // bir sayfa ileri
history.go(-2); // iki sayfa geri
history.length; // bu sekmenin geçmişinde kaç kayıt var
Güvenlik gereği geçmişteki adresleri okuyamazsın; sadece kaç kayıt olduğunu bilir ve aralarında gezinirsin. Sayfayı yenilemeden adres çubuğunu değiştirmeyi sağlayan pushState'i de yine Orta seride göreceğiz.
navigator ve screen: Tarayıcıyı ve Ekranı Tanımak
Bu dosyayı kaydedip aç, sonra pencerenin boyutunu değiştir:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Browser Info</title>
</head>
<body>
<p id="language"></p>
<p id="connection"></p>
<p id="size"></p>
<button id="back">Go back</button>
<script>
const language = document.getElementById("language");
const connection = document.getElementById("connection");
const size = document.getElementById("size");
language.textContent = `Browser language: ${navigator.language}`;
function showConnection() {
connection.textContent = navigator.onLine ? "You're on a network." : "You seem to be offline.";
}
function showSize() {
size.textContent = `Window: ${window.innerWidth} x ${window.innerHeight}, screen: ${screen.width} x ${screen.height}`;
}
showConnection();
showSize();
window.addEventListener("online", showConnection);
window.addEventListener("offline", showConnection);
window.addEventListener("resize", showSize);
document.getElementById("back").addEventListener("click", () => history.back());
</script>
</body>
</html>
navigator.language kullanıcının tarayıcı dilini verir, örneğin "en-US" ya da "tr-TR". Tercih sırasına göre bütün dilleri navigator.languages array'inde bulursun. Sayfanı kullanıcının diliyle açmak için iyi bir başlangıç noktasıdır.
navigator.onLine cihazın bir ağa bağlı olup olmadığını söyler ve window üzerindeki online ve offline event'leriyle değişimi haber alırsın. Denemek için DevTools'un Network sekmesinde bağlantıyı Offline'a çek. Yalnız dikkat: true değeri internete erişebildiğin anlamına gelmez, sadece bir ağa bağlı olduğunu gösterir. Bunu bir özelliği kapatmak için değil, kullanıcıya "bağlantın kopmuş olabilir" gibi bir ipucu vermek için kullan.
navigator.clipboard panoya yazıp okumanı sağlar: navigator.clipboard.writeText("Hello"). HTTPS gibi güvenli bir bağlam ister ve genelde bir tıklama gibi kullanıcı hareketinin ardından çalışır. Sonucunu bir promise ile döndürdüğü için ayrıntısını Orta seride, asenkron programlamayı öğrendikten sonra göreceğiz. navigator.userAgent'a bakarak "bu hangi tarayıcı?" tahmini yapmaktan da kaçın. Bir özellik var mı diye doğrudan sor: if ("clipboard" in navigator).
screen.width ve screen.height monitörün tamamını, window.innerWidth ve innerHeight ise sayfanın görünen alanını verir. Pencereyi küçülttükçe değişen ikincisidir. Sayfanın düzenini ekrana göre uyarlamanın asıl yeri yine de CSS media query'leridir; bu değerleri JavaScript'te gerçekten bir hesap yapman gerektiğinde kullan.
Zamanlayıcılar: setTimeout ve setInterval
setTimeout bir fonksiyonu belirli bir süre sonra bir kez çalıştırır. setInterval ise belirli aralıklarla tekrar tekrar çalıştırır. İkisi de bir id döndürür; bu id'yi clearTimeout ya da clearInterval'a vererek zamanlayıcıyı iptal edersin. Bir geri sayım yapalım:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Countdown</title>
</head>
<body>
<p id="counter">10</p>
<button id="start">Start</button>
<button id="stop">Stop</button>
<p id="message"></p>
<script>
const counterArea = document.getElementById("counter");
const message = document.getElementById("message");
let remaining = 10;
let intervalId = null;
document.getElementById("start").addEventListener("click", () => {
if (intervalId !== null) return; // zaten çalışıyor
if (remaining === 0) remaining = 10;
intervalId = setInterval(() => {
remaining = remaining - 1;
counterArea.textContent = remaining;
if (remaining === 0) {
clearInterval(intervalId);
intervalId = null;
message.textContent = "Time's up!";
setTimeout(() => {
message.textContent = "";
}, 3000);
}
}, 1000);
});
document.getElementById("stop").addEventListener("click", () => {
clearInterval(intervalId);
intervalId = null;
});
</script>
</body>
</html>
Start butonuna basınca her saniye sayı bir azalıyor. Sıfıra gelince clearInterval ile tekrarı durduruyor, "Time's up!" yazıp üç saniye sonra setTimeout ile mesajı siliyoruz. intervalId'yi kontrol etmemizin sebebi şu: Start butonuna iki kez basılırsa iki ayrı interval çalışır ve sayaç iki kat hızlı akar.
Şimdi baştaki sorunun cevabı: konsolda sırasıyla 1, 3, 2 görürsün. setTimeout fonksiyonu o an çalıştırmaz, "en az şu kadar süre sonra çalıştır" diye bir kenara not eder. Sıfır milisaniye bile versen, zamanlayıcının fonksiyonu ancak o an çalışan kod tamamen bittikten sonra sıra bulur. Bu yüzden önce 3 yazılır. Bunun arkasındaki mekanizmanın adı event loop ve onu Orta seride adım adım inceleyeceğiz. Şimdilik şunu akılda tut: verdiğin süre bir garanti değil, bir alt sınırdır. Üstelik tarayıcılar arka planda kalan sekmelerdeki zamanlayıcıları pil ve performans için yavaşlatır.
alert, confirm ve prompt
Tarayıcının hazır üç diyalog kutusu var:
alert("Saved."); // sadece mesaj gösterir
const confirmed = confirm("Do you want to delete it?"); // true ya da false
const userName = prompt("What's your name?", "Guest"); // yazılan string ya da İptal'de null
console.log(confirmed, userName);
Kullanımı çok kolay ama gerçek projelerde nadiren tercih edilir. Diyalog açıkken bütün sayfa donar: kullanıcı başka hiçbir şeye tıklayamaz, senin kodun da o satırda bekler. Görünümünü değiştiremezsin, sitenin değil tarayıcının mesajı gibi durur ve kullanıcılar bu tür kutulara giderek daha az güvenir. Bazı tarayıcılar art arda açılan diyaloglarda kullanıcıya onları engelleme seçeneği bile sunar. Sayfanın içinde kendi mesaj alanını göstermek ya da HTML'in <dialog> element'ini kullanmak çok daha iyi bir deneyim verir. Hata ayıklarken de alert yerine console.log kullan.
Sık Düşülen Tuzaklar
Fonksiyonu vermek yerine çağırmak
setTimeout(greet(), 2000) yazarsan greet hemen çalışır ve iki saniye sonra hiçbir şey olmaz. Event'ler yazısındaki kural burada da aynı: setTimeout(greet, 2000).
Interval'ı durdurmayı unutmak
Bir setInterval, sen clearInterval diyene ya da sayfa kapanana kadar çalışmaya devam eder. Kullanıcı başka bir ekrana geçtiğinde bile arka planda iş yapmayı sürdürebilir. Bir interval kurduğun her yerde, onu nerede durduracağını da baştan düşün.
Zamanlayıcıya string vermek
setTimeout("console.log('hi')", 1000) da çalışır; tarayıcı string'i kod olarak yorumlar. Bu hem yavaştır hem de güvenlik riskidir. Her zaman bir fonksiyon ver.
navigator.onLine'a fazla güvenmek
true görmen, isteklerinin sunucuya ulaşacağını garanti etmez. Bağlantının gerçekten çalışıp çalışmadığını ancak bir istek yapıp sonucuna bakarak anlarsın.
Küçük Bir Deneme
★☆☆ Konsolda bir setTimeout ile beş saniye sonra sayfanın başlığını (document.title) "Still there?" yap.
★★☆ Çalıştırmadan önce çıktıyı tahmin et, sonra konsolda dene:
setTimeout(() => console.log("A"), 100);
setTimeout(() => console.log("B"), 0);
console.log("C");
★★★ Ekranda canlı bir saat göster: setInterval ile her saniye saati, dakikayı ve saniyeyi güncelle. Yanına bir "Stop / Resume" butonu koy. Bir de sekme başlığında pencerenin genişliğini göster ve pencere boyutu değiştikçe güncelle.
Son alıştırmada saati ekrana yazmak için tarihe ve zamana dokunmak gerekiyor. Bir sonraki yazıda tam olarak bunu konuşacağız: JavaScript'te tarih oluşturmayı, iki tarih arasındaki farkı hesaplamayı ve tarihleri okunur biçimde göstermeyi.