Ders 11 / 14
Aktarım ve Hedefleme
Sözdizim indirgeme ile yetenek dolgusunun ayrımı, hedef kümesinin belirlenmesi, aktarımın çözemediği sorunlar ve kaynak dilin hedef dilden farklı olduğu durumlar.
İçindekiler
Önceki ders modülleri tek çıktıda birleştirdi ve kaynağın yazıldığı sözdizimin hedef ortamda tanınacağını varsaydı. Bu varsayım her zaman doğru değildir.
Kaynağı hedefin anlayacağı biçime çeviren dönüşüme aktarım (transpilation) denir. Aktarım tek bir iş gibi görünür; aslında iki ayrı sorunu çözer ve ikisinin çözümü birbirinden bağımsızdır.
İki Ayrı Sorun
Sözdizim sorunu ayrıştırma düzeyindedir. Hedef, kaynağın kullandığı yazımı tanımıyorsa dosyayı okuyamaz bile; hata, tek bir satır çalışmadan çıkar. Çözümü, aynı anlamı hedefin tanıdığı yapılarla ifade etmektir.
Yetenek sorunu çalışma zamanı düzeyindedir. Hedef dosyayı ayrıştırabilir ama çağrılan bir işlev veya erişilen bir nesne orada bulunmayabilir. Hata, ilgili satıra gelindiğinde çıkar. Çözümü, eksik yeteneği çalışma anında tanımlamaktır.
Ayrımın pratik sonucu şudur: ilk sorun derleme anında, ikincisi çalışma anında çözülür. Bir araç ikisini birlikte yapıyor olabilir, ama ürettikleri farklıdır — biri kaynağı değiştirir, diğeri çıktıya kod ekler.
Sözdizim İndirgeme
Sözdizim indirgeme (downleveling), bir yapıyı daha eski bir yazımla aynı anlamda yeniden ifade etmektir. Ölçüm kütüphanesinden bir sınıf, üç ayrı özellik kullanır: özel alan, erişimci ve alan konumunda tanımlanmış ok fonksiyonu.
// dosya: kaynak.mjs export class Olcum { #sozcukler; constructor(sozcukler) { this.#sozcukler = sozcukler; } get sayi() { return this.#sozcukler.length; } enUzun = () => this.#sozcukler.reduce((en, s) => (s.length > en.length ? s : en), ''); } const olcum = new Olcum(['bir', 'ikinci', 'ucuncu-sozcuk']); console.log(olcum.sayi, olcum.enUzun());
Aynı anlamın, bu üç özelliğin hiçbirini kullanmayan karşılığı:
// dosya: hedef.js 'use strict'; var _sozcukler = new WeakMap(); function Olcum(sozcukler) { var kendisi = this; _sozcukler.set(this, sozcukler); this.enUzun = function () { return _sozcukler.get(kendisi).reduce(function (en, s) { return s.length > en.length ? s : en; }, ''); }; } Object.defineProperty(Olcum.prototype, 'sayi', { get: function () { return _sozcukler.get(this).length; }, }); var olcum = new Olcum(['bir', 'ikinci', 'ucuncu-sozcuk']); console.log(olcum.sayi, olcum.enUzun());
$ node kaynak.mjs
3 ucuncu-sozcuk
$ node hedef.js
3 ucuncu-sozcuk
$ wc -c kaynak.mjs hedef.js
356 kaynak.mjs
521 hedef.js
877 total
Davranış aynı, boyut yarı yarıya büyük. İndirgeme bedava değildir ve bedeli üç kalemdir:
Boyut. Her indirgenen yapı daha uzun bir karşılıkla yazılır.
Başarım. Özel alanın zayıf eşleme (weak map) ile taklit edilmesi, doğrudan alan erişiminden pahalıdır. Sınıf sözdizimindeki bazı yapıların indirgenmiş karşılıkları, motorun eniyilediği yollardan çıkar.
Anlam yaklaşıklığı. Taklit tam değildir. Yukarıdaki karşılıkta #sozcukler alanı
gerçekten erişilemez değildir; _sozcukler adlı eşlemeye ulaşan kod onu okuyabilir.
JavaScript’te Nesneler ve Fonksiyonlar kursunda tanıtılan özel alan güvencesi indirgemede
korunamaz.
Yetenek Dolgusu
İkinci sorunun çözümü, eksik yeteneği çalışma anında tanımlamaktır; buna yetenek dolgusu (polyfill) denir. Doğru kalıp, yeteneği önce sınamak ve yalnızca eksikse tanımlamaktır.
Kalıbı gerçekten sınamak için eksik bir ortam gerekir. Çalışma zamanının yalıtılmış bağlam düzeneği, bir yeteneği kaldırarak böyle bir ortamı üretmeye yarar:
// dosya: dolgu.mjs import vm from 'node:vm'; const eskiOrtam = vm.createContext({ console }); // Yeteneği ortamdan kaldırarak eski bir çalışma zamanını taklit ediyoruz. vm.runInContext('delete Array.prototype.at;', eskiOrtam); vm.runInContext('console.log("dolgu öncesi:", typeof [].at);', eskiOrtam); const dolgu = ` if (typeof Array.prototype.at !== 'function') { Object.defineProperty(Array.prototype, 'at', { value: function (dizin) { const n = Math.trunc(dizin) || 0; return this[n < 0 ? this.length + n : n]; }, writable: true, configurable: true, enumerable: false, }); } `; vm.runInContext(dolgu, eskiOrtam); vm.runInContext('console.log("dolgu sonrası:", typeof [].at, [10, 20, 30].at(-1));', eskiOrtam); // Ana ortam etkilenmedi. console.log('ana ortam:', typeof [].at, [10, 20, 30].at(-1));
$ node dolgu.mjs dolgu öncesi: undefined dolgu sonrası: function 30 ana ortam: function 30
Üç ayrıntı kalıbın parçasıdır. Sınama, sürüm sorgusuyla değil yeteneğin kendisiyle yapılır: ortamın kimliği değil, aranan işlevin varlığı sorulur. Tanım, sıradan atama yerine özellik tanımlayıcısıyla yapılır; böylece sayılabilirlik kapatılır ve yerleşik yöntemlerin davranışı taklit edilir. Son olarak yetenek dolgusu, yerleşik bir nesneyi değiştirdiği için tüm programı etkiler — bu yüzden dolgular giriş noktasında bir kez yüklenir, kütüphane modüllerinin içine serpiştirilmez.
Bir kütüphane, tükettiği ortamın yerleşiklerini değiştirmemelidir. Kütüphanenin doğru davranışı, eksik yeteneği kendi içinde bir yardımcı işlevle karşılamaktır; yerleşiği değiştirme kararı uygulamanındır.
Hedef Kümesi
Hangi yapıların indirgeneceğine ve hangi yetenek dolgularının ekleneceğine karar veren şey hedef kümesidir: çıktının çalışması istenen ortamların listesi. Küme genişledikçe daha fazla indirgeme yapılır, çıktı büyür ve başarım düşer.
Kümeyi belirlerken iki hata sıktır. Birincisi, kümeyi gereğinden geniş tutmaktır: hiç kullanılmayan ortamlar için ödenen boyut ve başarım, gerçek kullanıcıların maliyetidir. İkincisi, kümeyi yazmamaktır — varsayılan bir liste, projenin gerçek kullanıcılarına uymayabilir.
Doğru yaklaşım kümeyi yazılı ve gerekçeli tutmaktır. Küme, çıktının hangi ortamlarda çalışacağını bildiren bir sözleşmedir; sözleşmenin dışındaki ortamlarda çıktının çalışması beklenmez. Kütüphane paketlerinde bu bilgi belgelenmelidir, çünkü tüketicinin hedef kümesi kütüphanenin kümesini kapsamak zorundadır.
Aktarımın Yapamadıkları
Aktarımın sınırları, hedeflemenin sınırlarıdır.
Motor ilkelleri taklit edilemez. Yeni bir ilkel tip, çöp toplayıcıya bağlı bir yapı ya da bellek düzeni gerektiren bir yetenek, kütüphane koduyla yazılamaz. Böyle bir yeteneğin dolgusu ya yaklaşık olur ya da hiç olmaz.
Anlam farkları kalır. Özel alan örneğinde görüldüğü gibi, indirgenmiş karşılık aynı gözlemlenebilir davranışı vermeyebilir. Farklar genellikle uç durumlarda görünür ve sınamalarda yakalanmayabilir.
Başarım geri gelmez. İndirgenmiş kod, hedefin yerel desteğinden yararlanamaz.
Bu üç sınır, hedeflemenin bir ödünleşim olduğunu gösterir: geniş bir küme daha çok kullanıcı, daha büyük ve daha yavaş bir çıktı demektir. Karar ölçülerek verilmelidir.
Kaynak Dilin Farklı Olması
Aktarımın kapsamı yalnızca sürüm farkı değildir. Kaynak, hedef dilden başka bir dil de olabilir; araç o dili okur ve hedefin çalıştırabileceği bir çıktı üretir. Bu durumda dönüşüm iki iş yapar: kaynak dile özgü yapıları karşılamak ve kaynak dilin taşıdığı ek bilgiyi çıktıdan çıkarmak.
En yaygın örnek tip bilgisidir: kaynakta yazılı tipler derleme anında denetlenir, çıktıya yazılmaz. Bu, dönüşümün en ucuz biçimidir — çıktı, kaynağın tip açıklamaları silinmiş hâlinden ibarettir. Kursun son dersinde bağlanacağı yer burasıdır.
Kaynak ile çıktının ayrışması, bu dersin bıraktığı asıl sorundur. Hata bir yığıt izi verdiğinde, izdeki satır numaraları çıktıya aittir; kaynağa değil. Aktarım ne kadar kapsamlıysa bu iki dosya birbirinden o kadar uzaktır.
Özet
- Aktarım iki ayrı sorunu çözer: hedefin tanımadığı sözdizim ve hedefte bulunmayan yetenek; ilki derleme anında, ikincisi çalışma anında çözülür.
- Sözdizim indirgeme çıktıyı büyütür, başarımı düşürür ve bazı anlam güvencelerini yaklaşık hâle getirir.
- Yetenek dolgusu, sürüm sorgusuyla değil yeteneğin varlığıyla koşullanır; yerleşikleri değiştirdiği için uygulamanın giriş noktasına aittir, kütüphanelere değil.
- Hedef kümesi, çıktının hangi ortamlarda çalışacağını bildiren yazılı bir sözleşmedir; gereğinden geniş tutulması gerçek kullanıcılara maliyet çıkarır.
- Motor ilkelleri taklit edilemez, anlam farkları kalır ve indirgenmiş kod yerel desteğin başarımına ulaşamaz.
Sonraki Adım
Çıktı artık kaynaktan farklı bir dosyadır: satırları kaymış, yapıları değişmiş, adları yeniden yazılmış olabilir. Bir hata oluştuğunda geliştiricinin gördüğü satır numarası üretilmiş dosyaya aittir. Sonraki ders, üretilmiş konumdan kaynak konuma geri dönmeyi sağlayan eşleme dosyasını ve bu dosyanın nasıl üretildiğini ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.