JavaScript

Olay delegasyonunu açıklayın

Olay delegasyonu, alt öğelere olay dinleyicileri eklemek yerine bir üst öğeye olay dinleyicileri eklemeyi içeren bir tekniktir. Dinleyici, DOM'da olay kabarcıklanması nedeniyle alt öğelerde olay tetiklendiğinde tetiklenir. Bu tekniğin faydaları şunlardır:

  • Her bir alt öğeye olay işleyicileri eklemek zorunda kalmak yerine, ana öğede yalnızca tek bir işleyiciye ihtiyaç duyulduğu için bellek ayak izi azalır.
  • Kaldırılan öğelerden işleyiciyi ayırmaya ve yeni öğeler için olayı bağlamaya gerek yoktur.

JavaScript'te `this`'in nasıl çalıştığını açıklayın

this için basit bir açıklama yok; JavaScript'in en kafa karıştırıcı kavramlarından biri. Kabaca bir açıklama, this'in değerinin fonksiyonun nasıl çağrıldığına bağlı olduğudur. this hakkında internette birçok açıklama okudum ve [Arnav Aggrawal]'ın açıklamasını en net buldum. Aşağıdaki kurallar uygulanır:

  1. Fonksiyon çağrılırken new anahtar kelimesi kullanılırsa, fonksiyon içindeki this yepyeni bir nesnedir.
  2. Bir fonksiyonu çağırmak/oluşturmak için apply, call veya bind kullanılıyorsa, fonksiyon içindeki this, argüman olarak iletilen nesnedir.
  3. Bir fonksiyon obj.method() gibi bir yöntem olarak çağrılırsa - this, fonksiyonun bir özelliği olduğu nesnedir.
  4. Bir fonksiyon, yukarıdaki koşullardan herhangi biri olmadan çağrılırsa, yani serbest bir fonksiyon çağrısı olarak çağrılırsa, this genel nesnedir. Bir tarayıcıda bu, window nesnesidir. Katı modda ('use strict') ise, this genel nesne yerine undefined olacaktır.
  5. Yukarıdaki kurallardan birden fazlası uygulanıyorsa, daha yüksek olan kural kazanır ve this değerini ayarlar.
  6. Fonksiyon bir ES2015 ok fonksiyonu ise, yukarıdaki tüm kuralları göz ardı eder ve oluşturulduğu zamanki çevreleyen kapsamının this değerini alır.

Derinlemesine bir açıklama için [Medium'daki makalesine] göz atın.

this ile çalışmanın ES6'da değiştiği yollardan birine örnek verebilir misiniz?

ES6, [kapsayan sözcüksel kapsamı] kullanan [ok fonksiyonlarını] kullanmanıza olanak tanır. Bu genellikle kullanışlıdır, ancak çağıranın .call veya .apply aracılığıyla bağlamı kontrol etmesini engeller; bunun sonucu olarak jQuery gibi bir kütüphane, olay işleyici fonksiyonlarınızda this'i düzgün bir şekilde bağlamayacaktır. Bu nedenle, büyük eski uygulamaları yeniden düzenlerken bunu akılda tutmak önemlidir.

Prototip tabanlı kalıtımın nasıl çalıştığını açıklayın

Tüm JavaScript nesnelerinin, Object.create(null) ile oluşturulan nesneler dışında, başka bir nesneye referans olan ve nesnenin "prototipi" olarak adlandırılan bir __proto__ özelliği vardır. Bir nesnede bir özelliğe erişildiğinde ve özellik o nesnede bulunamazsa, JavaScript motoru nesnenin __proto__'sına, ve __proto__'nun __proto__'suna vb. bakar, ta ki özelliği __proto__'lardan birinde bulana veya prototip zincirinin sonuna ulaşana kadar. Bu davranış klasik kalıtımı simüle eder, ancak aslında [mirastan çok delegasyondur].

Prototip Tabanlı Kalıtım Örneği

// Üst nesne yapılandırıcısı. function Animal(name) { this.name = name; } // Üst nesnenin prototipine bir yöntem ekleyin. Animal.prototype.makeSound = function () { console.log('The ' + this.constructor.name + ' makes a sound.'); }; // Alt nesne yapılandırıcısı. function Dog(name) { Animal.call(this, name); // Üst yapılandırıcıyı çağırın. } // Alt nesnenin prototipini üst nesnenin prototipi olarak ayarlayın. Object.setPrototypeOf(Dog.prototype, Animal.prototype); // Alt nesnenin prototipine bir yöntem ekleyin. Dog.prototype.bark = function () { console.log('Woof!'); }; // Yeni bir Dog örneği oluşturun. const bolt = new Dog('Bolt'); // Alt nesnede yöntemleri çağırın. console.log(bolt.name); // "Bolt" bolt.makeSound(); // "The Dog makes a sound." bolt.bark(); // "Woof!"

Dikkat edilmesi gerekenler şunlardır:

  • .makeSound Dog üzerinde tanımlı değil, bu yüzden motor prototip zincirini yukarı çıkar ve devralınan Animal'dan .makeSound'ı bulur.
  • Kalıtım zincirini oluşturmak için Object.create kullanılması artık önerilmez. Bunun yerine Object.setPrototypeOf kullanın.

AMD ile CommonJS hakkında ne düşünüyorsunuz?

Her ikisi de, ES2015 gelene kadar JavaScript'te doğal olarak bulunmayan bir modül sistemini uygulamanın yollarıdır. CommonJS senkron iken AMD (Asynchronous Module Definition) açıkça asenkrondur. CommonJS sunucu tarafı geliştirme göz önünde bulundurularak tasarlanmıştır, AMD ise modüllerin asenkron yüklemesini desteklemesiyle tarayıcılar için daha çok amaçlanmıştır.

AMD sözdizimini oldukça ayrıntılı buluyorum ve CommonJS, diğer dillerde import ifadelerini yazacağınız stile daha yakın. Çoğu zaman, AMD'yi gereksiz buluyorum, çünkü tüm JavaScript'inizi tek bir birleştirilmiş paket dosyasına servis ederseniz, asenkron yükleme özelliklerinden yararlanamazsınız. Ayrıca, CommonJS sözdizimi Node'un modül yazma stiline daha yakındır ve istemci tarafı ile sunucu tarafı JavaScript geliştirme arasında geçiş yaparken daha az bağlam değiştirme yükü vardır.

Hem senkron hem de asenkron yüklemeyi destekleyen ES2015 modülleriyle nihayet tek bir yaklaşıma bağlı kalabileceğimiz için mutluyum. Tarayıcılarda ve Node'da tam olarak kullanıma sunulmamış olsa da, kodumuzu dönüştürmek için her zaman dönüştürücüler kullanabiliriz.

Aşağıdaki ifadenin neden bir IIFE olarak çalışmadığını açıklayın: `function foo(){ }();`. Doğru bir IIFE yapmak için neyin değiştirilmesi gerekir?

IIFE, Anında Çağrılan Fonksiyon İfadeleri anlamına gelir. JavaScript ayrıştırıcısı function foo(){ }(); ifadesini function foo(){ } ve (); olarak okur; burada ilki bir fonksiyon bildirimi, ikincisi (bir çift parantez) bir fonksiyonu çağırma girişimi ancak belirtilen bir ad olmadığı için Uncaught SyntaxError: Unexpected token ) hatası verir.

Bunu düzeltmenin daha fazla parantez eklemeyi içeren iki yolu vardır: (function foo(){ })() ve (function foo(){ }()). function ile başlayan ifadeler fonksiyon bildirimleri olarak kabul edilir; bu fonksiyonu () içine alarak bir fonksiyon ifadesi haline gelir ve daha sonra sonraki () ile yürütülebilir. Bu fonksiyonlar global kapsamda görünmez ve gövde içinde kendisine referans vermeniz gerekmiyorsa adını bile atlayabilirsiniz.

void operatörünü de kullanabilirsiniz: void function foo(){ }();. Ne yazık ki, böyle bir yaklaşımın bir sorunu var. Verilen ifadenin değerlendirilmesi her zaman undefined'dır, bu yüzden IIFE fonksiyonunuz herhangi bir şey döndürürse, onu kullanamazsınız. Bir örnek:

const foo = void (function bar() { return 'foo'; })(); console.log(foo); // undefined

`null`, `undefined` veya bildirilmemiş bir değişken arasındaki fark nedir? Bu durumların herhangi birini nasıl kontrol edersiniz?

Bildirilmemiş değişkenler, daha önce var, let veya const kullanılarak oluşturulmamış bir tanımlayıcıya bir değer atandığında oluşturulur. Bildirilmemiş değişkenler, mevcut kapsamın dışında, global olarak tanımlanacaktır. Katı modda, bildirilmemiş bir değişkene atama yapmaya çalıştığınızda bir ReferenceError fırlatılacaktır. Bildirilmemiş değişkenler, global değişkenler gibi kötüdür. Ne pahasına olursa olsun bunlardan kaçının! Onları kontrol etmek için, kullanımını bir try/catch bloğuna sarın.

function foo() { x = 1; // Katı modda ReferenceError fırlatır } foo(); console.log(x); // 1

undefined olan bir değişken, bildirilmiş ancak değer atanmamış bir değişkendir. undefined türündedir. Bir fonksiyon, yürütülmesi sonucunda herhangi bir değer döndürmezse ve bir değişkene atanırsa, değişkenin değeri de undefined olur. Bunu kontrol etmek için, sıkı eşitlik (===) operatörünü veya 'undefined' dizesini verecek olan typeof'u kullanarak karşılaştırın. Değer null ise de true döndüreceği için, kontrol etmek için soyut eşitlik operatörünü kullanmamanız gerektiğini unutmayın.

var foo; console.log(foo); // undefined console.log(foo === undefined); // true console.log(typeof foo === 'undefined'); // true console.log(foo == null); // true. Yanlış, bunu kontrol etmek için kullanmayın! function bar() {} var baz = bar(); console.log(baz); // undefined

null olan bir değişkene açıkça null değeri atanmış olacaktır. Hiçbir değeri temsil eder ve açıkça atanmış olması anlamında undefined'dan farklıdır. null'ı kontrol etmek için, sadece sıkı eşitlik operatörünü kullanarak karşılaştırın. Yukarıdaki gibi, undefined ise de true döndüreceği için soyut eşitlik operatörünü (==) kullanmamanız gerektiğini unutmayın.

var foo = null; console.log(foo === null); // true console.log(typeof foo === 'object'); // true console.log(foo == undefined); // true. Yanlış, bunu kontrol etmek için kullanmayın!

Kişisel bir alışkanlık olarak, değişkenlerimi asla bildirilmemiş veya atanmamış bırakmam. Henüz kullanmayı düşünmüyorsam, bildirdikten sonra açıkça null atarım. İş akışınızda bir linter kullanıyorsanız, bildirilmemiş değişkenlere referans vermediğinizi de kontrol edebilir.

Kapatma nedir ve nasıl/neden kullanırsınız?

Kapatma, bir fonksiyonun ve o fonksiyonun bildirildiği sözcüksel ortamın birleşimidir. "Sözcüksel" kelimesi, sözcüksel kapsamlamanın, bir değişkenin nerede mevcut olduğunu belirlemek için kaynak kodda bir değişkenin bildirildiği konumu kullanması gerçeğine atıfta bulunur. Kapatmalar, dış (kapsayan) fonksiyon döndükten sonra bile dış fonksiyonun değişkenlerine - kapsam zincirine - erişimi olan fonksiyonlardır.

Neden kullanırsınız?

  • Veri gizliliği / kapatmalarla özel yöntemlerin taklit edilmesi. Genellikle [modül kalıbında] kullanılır.
  • [Kısmi uygulamalar veya currying].

`.forEach` döngüsü ile `.map()` döngüsü arasındaki temel farkı ve birini diğerine neden tercih edeceğinizi açıklayabilir misiniz?

İkisi arasındaki farkları anlamak için, her bir fonksiyonun ne yaptığını inceleyelim.

forEach

  • Bir dizideki öğeler arasında yinelenir.
  • Her öğe için bir geri çağrı yürütür.
  • Bir değer döndürmez.
const a = [1, 2, 3]; const doubled = a.forEach((num, index) => { // num ve/veya index ile bir şeyler yapın. }); // doubled = undefined

map

  • Bir dizideki öğeler arasında yinelenir.
  • Her öğeyi bir fonksiyonda çağırarak yeni bir öğeye "eşler", sonuç olarak yeni bir dizi oluşturur.
const a = [1, 2, 3]; const doubled = a.map((num) => { return num * 2; }); // doubled = [2, 4, 6]

.forEach ve .map() arasındaki temel fark, .map()'in yeni bir dizi döndürmesidir. Sonuca ihtiyacınız varsa, ancak orijinal diziyi değiştirmek istemiyorsanız, .map() açık bir seçimdir. Yalnızca bir dizi üzerinde yinelemeniz gerekiyorsa, forEach iyi bir seçimdir.

Anonim fonksiyonlar için tipik bir kullanım durumu nedir?

Global kapsama değişken sızdırmalarını önlemek için bazı kodları yerel bir kapsam içinde kapsüllemek için IIFE'lerde kullanılabilirler.

(function () { // Burada bazı kodlar. })();

Bir kez kullanılan ve başka hiçbir yerde kullanılması gerekmeyen bir geri çağrı olarak. İşleyiciler, işlev gövdesini bulmak için başka bir yerde arama yapmak yerine, onları çağıran kodun içinde tanımlandığında kod daha bağımsız ve okunabilir görünecektir.

setTimeout(function () { console.log('Hello world!'); }, 1000);

Fonksiyonel programlama yapılarına veya Lodash'a argümanlar (geri çağrılara benzer).

const arr = [1, 2, 3]; const double = arr.map(function (el) { return el * 2; }); console.log(double); // [2, 4, 6]

Kodunuzu nasıl düzenlersiniz? (modül kalıbı, klasik kalıtım?)

Geçmişte, daha çok OOP yaklaşımını teşvik eden Backbone modellerimi kullandım, Backbone modelleri oluşturdum ve bunlara yöntemler ekledim.

Modül kalıbı hala harika, ancak bugünlerde Flux mimarisine dayalı tek yönlü veri akışını kullanan React/Redux kullanıyorum. Uygulamamın modellerini düz nesneler kullanarak temsil eder ve bu nesneleri manipüle etmek için yardımcı saf fonksiyonlar yazardım. Durum, diğer Redux uygulamalarında olduğu gibi eylemler ve indirgeyiciler kullanılarak manipüle edilir.

Mümkün olduğunca klasik kalıtım kullanmaktan kaçınıyorum. Kullandığımda ise [bu kurallara] bağlı kalıyorum.

Host nesneler ve yerel nesneler arasındaki fark nedir?

Yerel nesneler, ECMAScript spesifikasyonu tarafından tanımlanan JavaScript dilinin bir parçası olan String, Math, RegExp, Object, Function vb. gibi nesnelerdir.

Host nesneler, çalışma zamanı ortamı (tarayıcı veya Node) tarafından sağlanan window, XMLHTTPRequest vb. gibi nesnelerdir.

`function Person(){}`, `var person = Person()`, ve `var person = new Person()` arasındaki fark nedir?

Bu soru oldukça belirsiz. Amacının JavaScript'teki yapılandırıcılar hakkında soru sorduğunu tahmin ediyorum. Teknik olarak konuşursak, function Person(){} sadece normal bir fonksiyon bildirimidir. Gelenek, yapılandırıcı olarak kullanılacak fonksiyonlar için PascalCase kullanmaktır.

var person = Person() ifadesi, Person'ı bir fonksiyon olarak çağırır, bir yapılandırıcı olarak değil. Bu şekilde çağırmak, fonksiyonun bir yapılandırıcı olarak kullanılması amaçlandığında yaygın bir hatadır. Tipik olarak, yapılandırıcı hiçbir şey döndürmez, bu nedenle yapılandırıcıyı normal bir fonksiyon gibi çağırmak undefined döndürecektir ve bu, örnek olarak tasarlanan değişkene atanır.

var person = new Person() ifadesi, new operatörünü kullanarak Person.prototype'tan miras alan bir Person nesnesi örneği oluşturur. Alternatif olarak, Object.create(Person.prototype) gibi Object.create kullanılabilir.

function Person(name) { this.name = name; } var person = Person('John'); console.log(person); // undefined console.log(person.name); // Tanımsızın 'name' özelliğini okuyamıyor hatası: Uncaught TypeError: Cannot read property 'name' of undefined var person = new Person('John'); console.log(person); // Person { name: "John" } console.log(person.name); // "john"

`.call` ve `.apply` arasındaki fark nedir?

Hem .call hem de .apply fonksiyonları çağırmak için kullanılır ve ilk parametre fonksiyon içindeki this değeri olarak kullanılacaktır. Ancak, .call sonraki argümanlar olarak virgülle ayrılmış argümanlar alırken, .apply sonraki argüman olarak bir argüman dizisi alır. Bunu hatırlamanın kolay bir yolu, call için C ve virgülle ayrılmış ve apply için A ve bir argüman dizisidir.

function add(a, b) { return a + b; } console.log(add.call(null, 1, 2)); // 3 console.log(add.apply(null, [1, 2])); // 3

`Function.prototype.bind`'i açıklayın.

[MDN]'den kelimesi kelimesine alınmıştır:

bind() yöntemi, çağrıldığında this anahtar kelimesi sağlanan değere ayarlanmış yeni bir işlev oluşturur; yeni işlev çağrıldığında sağlanan herhangi bir argümandan önce belirli bir argüman dizisi gelir.

Deneyimlerime göre, bu, başka fonksiyonlara aktarmak istediğiniz sınıf yöntemlerindeki this değerini bağlamak için en kullanışlıdır. Bu, React bileşenlerinde sıkça yapılır.

`document.write()`'ı ne zaman kullanırsınız?

document.write(), document.open() tarafından açılan bir belge akışına bir metin dizesi yazar. document.write() sayfa yüklendikten sonra çalıştırıldığında, tüm belgeyi temizleyen (<head> ve <body> kaldırılır!) ve içeriği verilen parametre değeriyle değiştiren document.open'ı çağırır. Bu nedenle genellikle tehlikeli ve kötüye kullanıma açık olduğu kabul edilir.

document.write()'ın analitik kodlarında veya [yalnızca JavaScript etkinse çalışması gereken stilleri dahil etmek istediğinizde] kullanıldığını açıklayan bazı çevrimiçi cevaplar var. Hatta HTML5 şablonunda [betikleri paralel olarak yüklemek ve yürütme sırasını korumak] için bile kullanılıyor! Ancak, bu nedenlerin güncel olmayabileceğinden ve modern çağda document.write() kullanılmadan da başarılabileceğinden şüpheleniyorum. Bu konuda yanılıyorsam lütfen düzeltin.

Özellik algılama, özellik çıkarımı ve UA dizesini kullanma arasındaki fark nedir?

Özellik Algılama

Özellik algılama, bir tarayıcının belirli bir kod bloğunu destekleyip desteklemediğini anlamayı ve destekleyip desteklemediğine bağlı olarak farklı kod çalıştırmayı içerir, böylece tarayıcı bazı tarayıcılarda çökme/hata vermeden her zaman çalışan bir deneyim sağlayabilir. Örneğin:

if ('geolocation' in navigator) { // navigator.geolocation kullanılabilir } else { // Özelliğin eksikliğini ele al }

[Modernizr] özellik algılamayı yönetmek için harika bir kütüphanedir.

Özellik Çıkarımı

Özellik çıkarımı, özellik algılama gibi bir özelliği kontrol eder, ancak başka bir fonksiyonu kullanır çünkü onun da var olacağını varsayar, örneğin:

if (document.getElementsByTagName) { element = document.getElementById(id); }

Bu gerçekten önerilmez. Özellik algılama daha güvenlidir.

UA Dizisi

Bu, ağ protokolü eşlerinin talep eden yazılım kullanıcı aracısının uygulama türünü, işletim sistemini, yazılım satıcısını veya yazılım sürümünü tanımlamasını sağlayan, tarayıcı tarafından rapor edilen bir dizidir. navigator.userAgent aracılığıyla erişilebilir. Ancak, dizeyi ayrıştırmak zordur ve sahte olabilir. Örneğin, Chrome hem Chrome hem de Safari olarak rapor verir. Bu nedenle Safari'yi algılamak için Safari dizesini ve Chrome dizesinin yokluğunu kontrol etmeniz gerekir. Bu yöntemden kaçının.

Ajax'ı mümkün olduğunca detaylı açıklayın.

Ajax (asenkron JavaScript ve XML), asenkron web uygulamaları oluşturmak için istemci tarafında birçok web teknolojisini kullanan bir dizi web geliştirme tekniğidir. Ajax ile web uygulamaları, mevcut sayfanın görüntülenmesini ve davranışını etkilemeden sunucuya asenkron olarak (arka planda) veri gönderebilir ve alabilir. Veri alışverişi katmanını sunum katmanından ayırarak Ajax, web sayfalarının ve dolayısıyla web uygulamalarının, tüm sayfayı yeniden yüklemeye gerek kalmadan içeriği dinamik olarak değiştirmesine olanak tanır. Uygulamada, modern uygulamalar, JSON'un JavaScript'e özgü olmasının avantajları nedeniyle genellikle XML yerine JSON kullanır.

XMLHttpRequest API'si asenkron iletişim için sıklıkla kullanılır veya günümüzde fetch() API'si kullanılır.

Ajax kullanmanın avantajları ve dezavantajları nelerdir?

Avantajları

  • Daha iyi etkileşim. Sunucudan gelen yeni içerik, tüm sayfayı yeniden yüklemeye gerek kalmadan dinamik olarak değiştirilebilir.
  • Komut dosyaları ve stil sayfaları yalnızca bir kez istenmesi gerektiğinden sunucuya bağlantıları azaltır.
  • Bir sayfada durum korunabilir. JavaScript değişkenleri ve DOM durumu, ana kapsayıcı sayfa yeniden yüklenmediği için kalıcı olacaktır.
  • Temel olarak bir SPA'nın çoğu avantajı.

Dezavantajları

  • Dinamik web sayfalarını yer imlerine eklemek daha zordur.
  • Tarayıcıda JavaScript devre dışı bırakılmışsa çalışmaz.
  • Bazı web tarayıcıları JavaScript'i yürütmez ve JavaScript tarafından yüklenen içeriği görmez.
  • Veri almak için Ajax kullanan web sayfalarının, DOM'u güncellemek için büyük olasılıkla alınan uzak verileri istemci tarafı şablonlarla birleştirmesi gerekecektir. Bunun gerçekleşmesi için JavaScript'in tarayıcıda ayrıştırılması ve yürütülmesi gerekecek ve düşük seviyeli mobil cihazlar bununla zorlanabilir.
  • Temel olarak bir SPA'nın çoğu dezavantajı.

JSONP'nin nasıl çalıştığını açıklayın (ve neden aslında Ajax olmadığını).

JSONP (JSON with Padding), web tarayıcılarındaki alanlar arası politikaları aşmak için yaygın olarak kullanılan bir yöntemdir çünkü mevcut sayfadan farklı bir alan adına Ajax isteklerine izin verilmez.

JSONP, bir <script> etiketi aracılığıyla ve genellikle callback sorgu parametresiyle (örneğin: https://example.com?callback=printData) farklı bir alan adına istekte bulunarak çalışır. Sunucu daha sonra veriyi printData adlı bir fonksiyon içinde sarar ve istemciye döndürür.

<script> function printData(data) { console.log(`My name is ${data.name}!`); } </script> <script src="[https://example.com?callback=printData](https://example.com?callback=printData)"></script>
printData({ name: 'Yang Shun' });

İstemcinin printData fonksiyonuna global kapsamda sahip olması gerekir ve farklı alan adından gelen yanıt alındığında fonksiyon istemci tarafından yürütülecektir.

JSONP güvensiz olabilir ve bazı güvenlik sorunları vardır. JSONP aslında JavaScript olduğu için, JavaScript'in yapabileceği her şeyi yapabilir, bu nedenle JSONP verilerini sağlayan güvenilir olmalıdır.

Günümüzde [CORS] önerilen yaklaşımdır ve JSONP bir hile olarak görülmektedir.

Hiç JavaScript şablonlama kullandınız mı? Kullandıysanız, hangi kütüphaneleri kullandınız?

Evet. Handlebars, Underscore, Lodash, AngularJS ve JSX. AngularJS'deki şablonlamayı sevmedim çünkü yönergelerde çok fazla dize kullanıyordu ve yazım hataları fark edilmeden kalabilirdi. JSX, JavaScript'e daha yakın olduğu ve öğrenilecek neredeyse hiçbir sözdizimi olmadığı için yeni favorim. Günümüzde, üçüncü taraf koda güvenmeden şablonlar oluşturmanın hızlı bir yolu olarak ES2015 şablon dize değişmezlerini bile kullanabilirsiniz.

const template = `<div>My name is: ${name}</div>`;

Ancak, yukarıdaki yaklaşımda potansiyel bir XSS'in farkında olun, çünkü şablonlama kütüphanelerinde olduğu gibi içerikler sizin için kaçmaz.

"Hoisting"i açıklayın.

Hoisting, kodunuzdaki değişken bildirimlerinin davranışını açıklamak için kullanılan bir terimdir. var anahtar kelimesiyle bildirilen veya başlatılan değişkenlerin bildirimi, modüllerinin/fonksiyon düzeyindeki kapsamlarının en üstüne "taşınır", buna hoisting diyoruz. Ancak, yalnızca bildirim hoisted olur, atama (varsa) olduğu yerde kalır.

Bildirimin aslında taşınmadığını unutmayın - JavaScript motoru derleme sırasında bildirimleri ayrıştırır ve bildirimler ile kapsamları hakkında bilgi sahibi olur. Bu davranışı, bildirimlerin kapsamlarının en üstüne kaldırıldığını görselleştirerek anlamak daha kolaydır. Birkaç örnekle açıklayalım.

console.log(foo); // undefined var foo = 1; console.log(foo); // 1

Fonksiyon bildirimlerinin gövdesi hoisted olurken, fonksiyon ifadelerinin (değişken bildirimleri şeklinde yazılanlar) yalnızca değişken bildirimi hoisted olur.

// Fonksiyon Bildirimi console.log(foo); // [Function: foo] foo(); // 'FOOOOO' function foo() { console.log('FOOOOO'); } console.log(foo); // [Function: foo] // Fonksiyon İfadesi console.log(bar); // undefined bar(); // Uncaught TypeError: bar bir fonksiyon değil var bar = function () { console.log('BARRRR'); }; console.log(bar); // [Function: bar]

let ve const ile bildirilen değişkenler de hoisted olur. Ancak, var ve function'dan farklı olarak, başlatılmazlar ve bildirimden önce onlara erişmek bir ReferenceError istisnasıyla sonuçlanacaktır. Değişken, bloğun başlangıcından bildirim işlenene kadar bir "geçici ölü bölgede" bulunur.

x; // undefined y; // Reference error: y is not defined var x = 'local'; let y = 'local';

Olay kabarcıklanmasını açıklayın.

Bir DOM öğesinde bir olay tetiklendiğinde, bağlı bir dinleyici varsa olayı işlemeye çalışır, ardından olay üst öğesine doğru kabarcıklanır ve aynı şey olur. Bu kabarcıklanma, öğenin atalarına doğru document'a kadar gerçekleşir. Olay kabarcıklanması, olay delegasyonunun arkasındaki mekanizmadır.

Bir "nitelik" ile bir "özellik" arasındaki fark nedir?

Nitelikler HTML işaretlemesinde tanımlanırken, özellikler DOM'da tanımlanır. Farkı göstermek için, HTML'mizde şöyle bir metin alanı olduğunu hayal edin: <input type="text" value="Hello">.

const input = document.querySelector('input'); console.log(input.getAttribute('value')); // Hello console.log(input.value); // Hello

Ancak metin alanının değerini "World!" ekleyerek değiştirdikten sonra bu şöyle olur:

console.log(input.getAttribute('value')); // Hello console.log(input.value); // Hello World!

Yerleşik JavaScript nesnelerini genişletmek neden iyi bir fikir değil?

Yerleşik/yerel bir JavaScript nesnesini genişletmek, onun prototype'ına özellikler/fonksiyonlar eklemek anlamına gelir. Bu ilk başta iyi bir fikir gibi görünse de, pratikte tehlikelidir. Kodunuzun her ikisi de Array.prototype'ı aynı contains yöntemini ekleyerek genişleten birkaç kütüphane kullandığını hayal edin, uygulamalar birbirini üzerine yazacak ve bu iki yöntemin davranışı aynı değilse kodunuz bozulacaktır.

Yerel bir nesneyi genişletmek isteyebileceğiniz tek zaman, bir polyfill oluşturmak istediğiniz zamandır, yani JavaScript spesifikasyonunun bir parçası olan ancak eski bir tarayıcı olması nedeniyle kullanıcının tarayıcısında bulunmayabilecek bir yöntem için kendi uygulamanızı sağlamaktır.

Doküman `load` olayı ile doküman `DOMContentLoaded` olayı arasındaki fark nedir?

DOMContentLoaded olayı, başlangıçtaki HTML belgesi tamamen yüklendiğinde ve ayrıştırıldığında tetiklenir, stil sayfalarının, görüntülerin ve alt çerçevelerin yüklenmesinin bitmesini beklemez.

window'un load olayı ise yalnızca DOM ve tüm bağımlı kaynaklar ve varlıklar yüklendikten sonra tetiklenir.

`==` ve `===` arasındaki fark nedir?

== soyut eşitlik operatörü, === ise katı eşitlik operatörüdür. == operatörü, gerekli tür dönüştürmelerini yaptıktan sonra eşitliği karşılaştırır. === operatörü tür dönüştürme yapmaz, bu nedenle iki değer aynı türde değilse === basitçe false döndürür. == kullanırken, şöyle tuhaf şeyler olabilir:

1 == '1'; // true 1 == [1]; // true 1 == true; // true 0 == ''; // true 0 == '0'; // true 0 == false; // true

Sizlere tavsiyem, == operatörünü asla kullanmamanızdır, ancak null veya undefined ile karşılaştırırken, a == null ifadesinin a null veya undefined ise true döndüreceği durumlarda kolaylık sağlaması dışında.

var a = null; console.log(a == null); // true console.log(a == undefined); // true

JavaScript ile ilgili aynı kaynak politikasını açıklayın.

Aynı kaynak politikası, JavaScript'in alan adı sınırları arasında istek yapmasını engeller. Bir kaynak, URI şeması, ana bilgisayar adı ve bağlantı noktası numarasının birleşimi olarak tanımlanır. Bu politika, bir sayfadaki kötü niyetli bir betiğin, o sayfanın Belge Nesne Modeli aracılığıyla başka bir web sayfasındaki hassas verilere erişmesini engeller.

Bunu çalıştırın:

duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5]
function duplicate(arr) { return arr.concat(arr); } duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5]

Ya da ES6 ile:

const duplicate = (arr) => [...arr, ...arr]; duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5]

Neden Üçlü ifade denir, "Üçlü" kelimesi neyi ifade eder?

"Üçlü" üçü belirtir ve üçlü bir ifade üç işleneni kabul eder: test koşulu, "o zaman" ifadesi ve "aksi takdirde" ifadesi. Üçlü ifadeler JavaScript'e özgü değildir ve neden bu listede yer aldığından emin değilim.

`"use strict";` nedir? Kullanımının avantajları ve dezavantajları nelerdir?

'use strict' ifadesi, tüm betiklere veya tek tek fonksiyonlara katı modu etkinleştirmek için kullanılır. Katı mod, JavaScript'in kısıtlı bir varyantını seçmenin bir yoludur.

Avantajları:

  • Yanlışlıkla global değişkenler oluşturmayı imkansız hale getirir.
  • Aksi takdirde sessizce başarısız olacak atamaların istisna fırlatmasını sağlar.
  • Silinemeyen özellikleri silme girişimlerinin (önceden girişimin hiçbir etkisi olmazken) bir istisna fırlatmasını sağlar.
  • Fonksiyon parametre adlarının benzersiz olmasını gerektirir.
  • Global bağlamda this tanımsızdır.
  • Bazı yaygın kodlama hatalarını yakalar ve istisna fırlatır.
  • Kafa karıştırıcı veya kötü düşünülmüş özellikleri devre dışı bırakır.

Dezavantajları:

  • Bazı geliştiricilerin alışkın olabileceği birçok eksik özellik.
  • function.caller ve function.arguments'a artık erişim yok.
  • Farklı katı modlarda yazılmış betiklerin birleştirilmesi sorunlara neden olabilir.

Genel olarak, faydaların dezavantajlardan ağır bastığını düşünüyorum ve katı modun engellediği özelliklere güvenmek zorunda kalmadım. Katı modu kullanmayı tavsiye ederim.

`3`'ün katlarında **"fizz"**, `5`'in katlarında **"buzz"** ve `3` ile `5`'in katlarında **"fizzbuzz"** çıktısı veren, `100`'e kadar döngü yapan bir for döngüsü oluşturun.

[Paul Irish]'in bu FizzBuzz sürümüne göz atın.

for (let i = 1; i <= 100; i++) { let f = i % 3 == 0, b = i % 5 == 0; console.log(f ? (b ? 'FizzBuzz' : 'Fizz') : b ? 'Buzz' : i); }

Ancak mülakatlarda yukarıdakini yazmanızı tavsiye etmem. Sadece uzun ama açık yaklaşıma bağlı kalın. FizzBuzz'ın daha çılgın versiyonları için aşağıdaki referans bağlantısına göz atın.

Bir web sitesinin global kapsamını olduğu gibi bırakmak ve asla dokunmamak neden genel olarak iyi bir fikirdir?

Her betik global kapsama erişebilir ve herkes değişkenlerini tanımlamak için global ad alanını kullanırsa, çakışmaların meydana gelmesi muhtemeldir. Değişkenlerinizi yerel bir ad alanı içinde kapsüllemek için modül kalıbını (IIFE'ler) kullanın.

`load` olayı gibi bir şeyi neden kullanırsınız? Bu olayın dezavantajları var mı? Başka alternatifler biliyor musunuz ve bunları neden kullanırsınız?

load olayı, belge yükleme sürecinin sonunda tetiklenir. Bu noktada, belgedeki tüm nesneler DOM'dadır ve tüm görüntüler, betikler, bağlantılar ve alt çerçeveler yüklemeyi tamamlamıştır.

DOM olayı DOMContentLoaded, sayfa için DOM oluşturulduktan sonra tetiklenir, ancak diğer kaynakların yüklenmesini beklemez. Bu, bazı durumlarda, başlatmadan önce tüm sayfanın yüklenmesine gerek duyulmadığında tercih edilir.

Tek sayfalık bir uygulamanın ne olduğunu ve onu nasıl SEO dostu yapacağınızı açıklayın.

Aşağıdaki metin, tesadüfen benim tarafımdan yazılmış harika [Grab Front End Guide]'dan alınmıştır!

Günümüzdeki web geliştiricileri, inşa ettikleri ürünleri web siteleri yerine web uygulamaları olarak adlandırıyorlar. İki terim arasında katı bir fark olmasa da, web uygulamaları genellikle oldukça etkileşimli ve dinamik olma eğilimindedir, kullanıcının eylemler gerçekleştirmesine ve eylemlerine yanıt almasına izin verir. Geleneksel olarak, tarayıcı sunucudan HTML alır ve onu işler. Kullanıcı başka bir URL'ye gittiğinde, tam sayfa yenileme gerekir ve sunucu yeni sayfaya taze, yeni HTML gönderir. Buna sunucu tarafı render denir.

Ancak, modern SPA'larda bunun yerine istemci tarafı render kullanılır. Tarayıcı, sunucudan tüm uygulama için gerekli komut dosyaları (çerçeveler, kütüphaneler, uygulama kodu) ve stil sayfaları ile birlikte ilk sayfayı yükler. Kullanıcı diğer sayfalara gittiğinde, sayfa yenilemesi tetiklenmez. Sayfanın URL'si [HTML5 History API] aracılığıyla güncellenir. Yeni sayfa için gerekli yeni veriler, genellikle JSON formatında, tarayıcı tarafından sunucuya [AJAX] istekleri aracılığıyla alınır. SPA daha sonra, ilk sayfa yüklemesinde zaten indirilmiş olan JavaScript aracılığıyla sayfayı dinamik olarak verilerle günceller. Bu model, yerel mobil uygulamaların çalışma şekline benzer.

Faydaları:

  • Uygulama daha duyarlı hissettirir ve kullanıcılar tam sayfa yenilemeler nedeniyle sayfa gezintileri arasındaki flaşı görmezler.
  • Aynı varlıkların her sayfa yüklemesi için tekrar indirilmesi gerekmediğinden sunucuya daha az HTTP isteği yapılır.
  • İstemci ve sunucu arasındaki sorumlulukların net bir şekilde ayrılması; API sözleşmesi bozulmadığı sürece, sunucu kodunu değiştirmeye gerek kalmadan farklı platformlar (örn. mobil, sohbet botları, akıllı saatler) için kolayca yeni istemciler oluşturabilirsiniz. Ayrıca, istemci ve sunucu üzerindeki teknoloji yığınını bağımsız olarak değiştirebilirsiniz.

Dezavantajları:

  • Birden çok sayfa için gerekli çerçeve, uygulama kodu ve varlıkların yüklenmesi nedeniyle daha ağır ilk sayfa yüklemesi.
  • Sunucunuzda yapılması gereken ek bir adım var: tüm istekleri tek bir giriş noktasına yönlendirmek ve istemci tarafı yönlendirmenin oradan devralmasına izin vermek için yapılandırmak.
  • SPA'lar içeriği render etmek için JavaScript'e bağımlıdır, ancak tüm arama motorları tarama sırasında JavaScript'i yürütmez ve sayfanızda boş içerik görebilirler. Bu, uygulamanızın Arama Motoru Optimizasyonuna (SEO) istemeden zarar verir. Ancak, çoğu zaman, uygulama oluştururken, SEO en önemli faktör değildir, çünkü tüm içeriğin arama motorları tarafından indekslenebilir olması gerekmez. Bunu aşmak için, uygulamanızı sunucu tarafında render edebilir veya [Prerender] gibi hizmetleri kullanarak "javascript'inizi bir tarayıcıda render edip, statik HTML'i kaydedip, tarayıcılara geri gönderebilirsiniz".

Promise'ler ve/veya polyfill'leri ile ilgili deneyiminizin kapsamı nedir?

Konu hakkında çalışma bilgisine sahibim. Promise, gelecekte tek bir değer üretebilecek bir nesnedir: ya çözülmüş bir değer ya da çözülmemiş bir neden (örneğin, bir ağ hatası oluştu). Bir Promise 3 olası durumdan birinde olabilir: yerine getirilmiş, reddedilmiş veya beklemede. Promise kullanıcıları, yerine getirilen değeri veya reddedilme nedenini ele almak için geri çağrıları ekleyebilirler.

Bazı yaygın polyfill'ler $.deferred, Q ve Bluebird'dir, ancak hepsi spesifikasyona uygun değildir. ES2015, Promise'leri kutudan çıkar çıkmaz destekler ve günümüzde polyfill'lere genellikle ihtiyaç duyulmaz.

Geri çağrılar yerine Promise'leri kullanmanın artıları ve eksileri nelerdir?

Artıları

  • Okunamayan geri çağrı cehennemini önler.
  • .then() ile okunabilir sıralı asenkron kod yazmayı kolaylaştırır.
  • Promise.all() ile paralel asenkron kod yazmayı kolaylaştırır.
  • Sadece geri çağrı içeren kodlamada mevcut olan şu senaryolar Promise'ler ile gerçekleşmez:
    • Geri çağrıyı çok erken çağırmak
    • Geri çağrıyı çok geç (veya hiç) çağırmak
    • Geri çağrıyı çok az veya çok fazla kez çağırmak
    • Gerekli ortam/parametreleri iletmeyi başaramamak
    • Oluşabilecek herhangi bir hata/istisnayı yutmak

Eksileri

  • Biraz daha karmaşık kod (tartışmalı).
  • ES2015'in desteklenmediği eski tarayıcılarda, kullanabilmek için bir polyfill yüklemeniz gerekir.

JavaScript'e derlenen bir dilde JavaScript kodu yazmanın bazı avantajları/dezavantajları nelerdir?

JavaScript'e derlenen dillere bazı örnekler arasında CoffeeScript, Elm, ClojureScript, PureScript ve TypeScript bulunmaktadır.

Avantajları:

  • JavaScript'teki bazı süregelen sorunları çözer ve JavaScript anti-kalıplarını caydırır.
  • JavaScript'in eksik olduğunu düşündüğüm bazı sentaks şekeri sağlayarak daha kısa kod yazmanızı sağlar, ancak ES2015 harika.
  • Zamanla bakımı yapılması gereken büyük projeler için statik tipler harikadır (TypeScript durumunda).

Dezavantajları:

  • Tarayıcılar yalnızca JavaScript çalıştırdığı için bir derleme/derleme işlemi gerektirir ve kodunuzun tarayıcılara sunulmadan önce JavaScript'e derlenmesi gerekir.
  • Kaynak haritalarınız önceden derlenmiş kaynağınıza düzgün bir şekilde eşleşmiyorsa hata ayıklama zor olabilir.
  • Çoğu geliştirici bu dillere aşina değildir ve öğrenmeleri gerekecektir. Projelerinizde kullanırsanız ekibiniz için bir öğrenme maliyeti söz konusudur.
  • Daha küçük bir topluluk (dile bağlı olarak), bu da kaynakların, eğitimlerin, kütüphanelerin ve araçların bulunmasının daha zor olacağı anlamına gelir.
  • IDE/düzenleyici desteği eksik olabilir.
  • Bu diller her zaman en son JavaScript standardının gerisinde kalacaktır.
  • Geliştiricilerin kodlarının neye derlendiğinin farkında olmaları gerekir - çünkü aslında çalışacak olan odur ve sonunda önemli olan budur.

Pratik olarak, ES2015 JavaScript'i büyük ölçüde geliştirmiş ve yazmayı çok daha keyifli hale getirmiştir. Günümüzde CoffeeScript'e gerçekten ihtiyaç duymuyorum.

JavaScript kodunda hata ayıklamak için hangi araçları ve teknikleri kullanırsınız?

  • React ve Redux
    • [React Geliştirici Araçları]
    • [Redux Geliştirici Araçları]
  • Vue
    • [Vue Geliştirici Araçları]
  • JavaScript
    • [Chrome Geliştirici Araçları]
    • debugger ifadesi
    • Eski güzel console.log hata ayıklaması

Nesne özelliklerini ve dizi öğelerini yinelemek için hangi dil yapılarını kullanırsınız?

Nesneler için:

  • for-in döngüleri - for (var property in obj) { console.log(property); }. Ancak bu, miras alınan özellikleri de yineleyecektir ve kullanmadan önce bir obj.hasOwnProperty(property) kontrolü eklemeniz gerekir.
  • Object.keys() - Object.keys(obj).forEach(function (property) { ... }). Object.keys() kendisine ilettiğiniz nesnenin tüm numaralandırılabilir özelliklerini listeleyen statik bir yöntemdir.
  • Object.getOwnPropertyNames() - Object.getOwnPropertyNames(obj).forEach(function (property) { ... }). Object.getOwnPropertyNames() kendisine ilettiğiniz nesnenin tüm numaralandırılabilir ve numaralandırılamaz özelliklerini listeleyen statik bir yöntemdir.

Diziler için:

  • for döngüleri - for (var i = 0; i < arr.length; i++). Buradaki yaygın tuzak, var'ın fonksiyon kapsamı içinde olması ve blok kapsamı içinde olmamasıdır ve çoğu zaman blok kapsamlı yineleyici değişkeni istersiniz. ES2015, blok kapsamına sahip let'i tanıtır ve bunun yerine onu kullanmanız önerilir. Dolayısıyla bu şöyle olur: for (let i = 0; i < arr.length; i++).
  • forEach - arr.forEach(function (el, index) { ... }). Bu yapı bazen daha uygun olabilir çünkü ihtiyacınız olan tek şey dizi öğeleriyse index'i kullanmak zorunda kalmazsınız. Ayrıca yinelemeyi erken sonlandırmanıza izin veren every ve some yöntemleri de vardır.
  • for-of döngüleri - for (let elem of arr) { ... }. ES6, String, Array, Map, Set vb. gibi yinelenebilir protokole uyan nesneler üzerinde döngü yapmanızı sağlayan yeni bir döngü, for-of döngüsünü tanıtır. for döngüsünün ve forEach() yönteminin avantajlarını birleştirir. for döngüsünün avantajı, ondan çıkabilmenizdir ve forEach()'in avantajı, bir sayaç değişkenine ihtiyacınız olmadığı için for döngüsünden daha kısa olmasıdır. for-of döngüsü ile hem bir döngüden çıkma yeteneğini hem de daha kısa bir sözdizimini elde edersiniz.

Çoğu zaman, .forEach yöntemini tercih ederim, ancak gerçekten ne yapmaya çalıştığınıza bağlıdır. ES6'dan önce, döngüyü break kullanarak erken sonlandırmamız gerektiğinde for döngülerini kullanıyorduk. Ama şimdi ES6 ile bunu for-of döngüleriyle yapabiliriz. Döngü başına yineleyiciyi birden fazla kez artırmak gibi daha fazla esnekliğe ihtiyacım olduğunda for döngülerini kullanırım.

Ayrıca, for-of döngüsünü kullanırken, her dizi öğesinin hem dizinine hem de değerine erişmeniz gerekiyorsa, bunu ES6 Array entries() yöntemi ve yapı bozma ile yapabilirsiniz:

const arr = ['a', 'b', 'c']; for (let [index, elem] of arr.entries()) { console.log(index, ': ', elem); }

Değişebilir ve değişmez nesneler arasındaki farkı açıklayın.

Değişmezlik, fonksiyonel programlamanın temel bir prensibidir ve nesne tabanlı programlara da sunacağı çok şey vardır. Değişebilir bir nesne, oluşturulduktan sonra durumu değiştirilebilen bir nesnedir. Değişmez bir nesne, oluşturulduktan sonra durumu değiştirilemeyen bir nesnedir.

JavaScript'te değişmez bir nesneye örnek nedir?

JavaScript'te bazı yerleşik tipler (sayılar, dizeler) değişmezdir, ancak özel nesneler genellikle değişebilir.

Bazı yerleşik değişmez JavaScript nesneleri Math, Date'dir.

Düz JavaScript nesnelerine değişmezlik eklemenin/simüle etmenin birkaç yolu şunlardır.

Nesne Sabit Özellikleri

writable: false ve configurable: false'ı birleştirerek, esasen bir nesne özelliği olarak bir sabit (değiştirilemez, yeniden tanımlanamaz veya silinemez) oluşturabilirsiniz, örneğin:

let myObject = {}; Object.defineProperty(myObject, 'number', { value: 42, writable: false, configurable: false, }); console.log(myObject.number); // 42 myObject.number = 43; console.log(myObject.number); // 42

Uzantıları Engelle

Bir nesnenin yeni özellikler eklenmesini engellemek, ancak nesnenin diğer özelliklerini olduğu gibi bırakmak istiyorsanız, Object.preventExtensions(...)'i çağırın:

var myObject = { a: 2, }; Object.preventExtensions(myObject); myObject.b = 3; myObject.b; // undefined

Katı olmayan modda, b'nin oluşturulması sessizce başarısız olur. Katı modda ise bir TypeError fırlatır.

Mühürle

Object.seal() "mühürlü" bir nesne oluşturur, bu da mevcut bir nesneyi alır ve esasen üzerinde Object.preventExtensions() çağırır, ancak aynı zamanda tüm mevcut özelliklerini configurable: false olarak işaretler.

Dolayısıyla, artık yeni özellikler ekleyemezsiniz, aynı zamanda mevcut hiçbir özelliği yeniden yapılandıramaz veya silemezsiniz (ancak değerlerini yine de değiştirebilirsiniz).

Dondur

Object.freeze() dondurulmuş bir nesne oluşturur, bu da mevcut bir nesneyi alır ve esasen üzerinde Object.seal() çağırır, ancak aynı zamanda tüm "veri erişimci" özelliklerini writable: false olarak işaretler, böylece değerleri değiştirilemez.

Bu yaklaşım, bir nesnenin kendisi için elde edebileceğiniz en yüksek değişmezlik seviyesidir, çünkü nesnede veya doğrudan özelliklerinde herhangi bir değişikliği engeller (ancak yukarıda belirtildiği gibi, başvurulan diğer nesnelerin içeriği etkilenmez).

var immutable = Object.freeze({});

Bir nesneyi dondurmak, nesneye yeni özellikler eklenmesine izin vermez ve mevcut özelliklerin kaldırılmasını veya değiştirilmesini engeller. Object.freeze() nesnenin numaralandırılabilirliğini, yapılandırılabilirliğini, yazılabilirliğini ve prototipini korur. Geçirilen nesneyi döndürür ve dondurulmuş bir kopyasını oluşturmaz.

Değişmezliğin artıları ve eksileri nelerdir?

Artıları

  • Daha kolay değişiklik algılama - Nesne eşitliği, referans eşitliği aracılığıyla performanslı ve kolay bir şekilde belirlenebilir. Bu, React ve Redux'ta nesne farklılıklarını karşılaştırmak için kullanışlıdır.
  • Değişmez nesnelerle programları düşünmek daha az karmaşıktır, çünkü bir nesnenin zamanla nasıl gelişebileceği konusunda endişelenmenize gerek yoktur.
  • Değişmez nesneler fonksiyonlardan döndürüldüğünde veya fonksiyonlara geçirildiğinde savunmacı kopyalar artık gerekli değildir, çünkü değişmez bir nesnenin onun tarafından değiştirilme olasılığı yoktur.
  • Referanslar aracılığıyla kolay paylaşım - Bir nesnenin bir kopyası diğer bir kopyası kadar iyidir, bu nedenle nesneleri önbelleğe alabilir veya aynı nesneyi birden çok kez yeniden kullanabilirsiniz.
  • İş parçacığı güvenli - Değişmez nesneler, çok iş parçacıklı bir ortamda iş parçacıkları arasında güvenle kullanılabilir, çünkü diğer eşzamanlı çalışan iş parçacıklarında değiştirilme riski yoktur.
  • ImmutableJS gibi kütüphaneleri kullanarak, nesneler yapısal paylaşım kullanılarak değiştirilir ve benzer yapılara sahip birden çok nesne için daha az bellek gerekir.

Eksileri

  • Değişmez veri yapılarının ve işlemlerinin saf uygulamaları, her seferinde yeni nesneler oluşturulduğu için son derece zayıf performansa neden olabilir. Yapısal paylaşımı kullanan verimli değişmez veri yapıları ve işlemleri için kütüphanelerin kullanılması önerilir.
  • Mevcut olanları değiştirmek yerine birçok küçük nesnenin tahsis edilmesi (ve serbest bırakılması) bir performans etkisine neden olabilir. Ayırıcı veya çöp toplayıcının karmaşıklığı genellikle yığında bulunan nesne sayısına bağlıdır.
  • Grafikler gibi döngüsel veri yapılarını oluşturmak zordur. Başlatmadan sonra değiştirilemeyen iki nesneniz varsa, onları birbirlerini gösterecek şekilde nasıl ayarlarsınız?

Kendi kodunuzda değişmezliği nasıl sağlayabilirsiniz?

Alternatif olarak, yukarıda belirtilen oluşturma teknikleriyle birlikte const bildirimlerini kullanmaktır. Nesneleri "değiştirmek" için, orijinal nesneyi değiştirmek yerine yeni nesneler oluşturmak için yayılma operatörünü, Object.assign'i, Array.concat()'ı vb. kullanın.

Örnekler:

// Dizi Örneği const arr = [1, 2, 3]; const newArr = [...arr, 4]; // [1, 2, 3, 4] // Nesne Örneği const human = Object.freeze({ race: 'human' }); const john = { ...human, name: 'John' }; // {race: "human", name: "John"} const alienJohn = { ...john, race: 'alien' }; // {race: "alien", name: "John"}

Senkron ve asenkron fonksiyonlar arasındaki farkı açıklayın.

Senkron fonksiyonlar engelleyicidir, asenkron fonksiyonlar ise değildir. Senkron fonksiyonlarda, sonraki ifade çalıştırılmadan önce ifadeler tamamlanır. Bu durumda, program tam olarak ifadelerin sırasına göre değerlendirilir ve ifadelerden biri çok uzun sürerse programın yürütülmesi duraklatılır.

Asenkron fonksiyonlar genellikle bir geri çağrı olarak bir parametre kabul eder ve yürütme, asenkron fonksiyon çağrıldıktan hemen sonra bir sonraki satırda devam eder. Geri çağrı, yalnızca asenkron işlem tamamlandığında ve çağrı yığını boş olduğunda çağrılır. Bir web sunucusundan veri yükleme veya bir veritabanını sorgulama gibi ağır işlemler asenkron olarak yapılmalıdır, böylece ana iş parçacığı o uzun işlemin tamamlanmasını beklemek yerine diğer işlemleri yürütmeye devam edebilir (tarayıcılar durumunda, kullanıcı arayüzü donar).

Olay döngüsü nedir? Çağrı yığını ile görev kuyruğu arasındaki fark nedir?

Olay döngüsü, çağrı yığınını izleyen ve görev kuyruğunda yapılacak herhangi bir iş olup olmadığını kontrol eden tek iş parçacıklı bir döngüdür. Çağrı yığını boşsa ve görev kuyruğunda geri çağırma fonksiyonları varsa, bir fonksiyon kuyruktan çıkarılır ve yürütülmek üzere çağrı yığınına itilir.

Philip Robert'ın Olay Döngüsü hakkındaki konuşmasına henüz göz atmadıysanız, atmalısınız. JavaScript hakkında en çok izlenen videolardan biridir.

`function foo() {}` ve `var foo = function() {}` arasındaki `foo` kullanımındaki farkları açıklayın.

Birincisi bir fonksiyon bildirimi, ikincisi ise bir fonksiyon ifadesidir. Temel fark, fonksiyon bildirimlerinin gövdesinin hoisted olması, ancak fonksiyon ifadelerinin gövdelerinin hoisted olmamasıdır (değişkenlerle aynı hoisting davranışına sahiptirler). Hoisting hakkında daha fazla açıklama için yukarıdaki hoisting hakkındaki soruya bakın. Bir fonksiyon ifadesini tanımlanmadan önce çağırmaya çalışırsanız, Uncaught TypeError: XXX bir fonksiyon değil hatası alırsınız.

Fonksiyon Bildirimi

foo(); // 'FOOOOO' function foo() { console.log('FOOOOO'); }

Fonksiyon İfadesi

foo(); // Uncaught TypeError: foo bir fonksiyon değil var foo = function () { console.log('FOOOOO'); };

`let`, `var` veya `const` kullanılarak oluşturulan değişkenler arasındaki farklar nelerdir?

var anahtar kelimesiyle bildirilen değişkenler, oluşturuldukları fonksiyona veya herhangi bir fonksiyonun dışında oluşturulmuşsa global nesneye kapsamlıdır. let ve const, blok kapsamlıdır, yani yalnızca en yakın küme parantezleri (fonksiyon, if-else bloğu veya for döngüsü) içinde erişilebilirler.

function foo() { // Tüm değişkenler fonksiyonlar içinde erişilebilir. var bar = 'bar'; let baz = 'baz'; const qux = 'qux'; console.log(bar); // bar console.log(baz); // baz console.log(qux); // qux } console.log(bar); // ReferenceError: bar tanımlı değil console.log(baz); // ReferenceError: baz tanımlı değil console.log(qux); // ReferenceError: qux tanımlı değil
if (true) { var bar = 'bar'; let baz = 'baz'; const qux = 'qux'; } // var ile bildirilen değişkenler, fonksiyon kapsamının herhangi bir yerinde erişilebilir. console.log(bar); // bar // let ve const ile tanımlanan değişkenler, tanımlandıkları bloğun dışında erişilemez. console.log(baz); // ReferenceError: baz tanımlı değil console.log(qux); // ReferenceError: qux tanımlı değil

var, değişkenlerin hoisted olmasına izin verir, yani kodda bildirilmeden önce referans verilebilirler. let ve const buna izin vermez, bunun yerine bir hata fırlatır.

console.log(foo); // undefined var foo = 'foo'; console.log(baz); // ReferenceError: 'baz' sözcüksel bildirimine başlatmadan önce erişilemez let baz = 'baz'; console.log(bar); // ReferenceError: 'bar' sözcüksel bildirimine başlatmadan önce erişilemez const bar = 'bar';

Bir değişkeni var ile yeniden bildirmek hata vermez, ancak let ve const hata verir.

var foo = 'foo'; var foo = 'bar'; console.log(foo); // "bar" let baz = 'baz'; let baz = 'qux'; // Uncaught SyntaxError: 'baz' tanımlayıcısı zaten bildirilmiş

let ve const, let'in değişkenin değerini yeniden atamasına izin vermesi, const'un ise izin vermemesi bakımından farklılık gösterir.

// Bu iyi. let foo = 'foo'; foo = 'bar'; // Bu bir istisnaya neden olur. const baz = 'baz'; baz = 'qux';

ES6 sınıfı ve ES5 fonksiyon yapılandırıcıları arasındaki farklar nelerdir?

Önce her birine bir örnekle bakalım:

// ES5 Fonksiyon Yapılandırıcısı function Person(name) { this.name = name; } // ES6 Sınıfı class Person { constructor(name) { this.name = name; } }

Basit yapılandırıcılar için oldukça benzer görünüyorlar.

Yapılandırıcılardaki ana fark kalıtım kullanıldığında ortaya çıkar. Person'dan türeyen ve bir studentId alanı ekleyen bir Student sınıfı oluşturmak istersek, yukarıdakilere ek olarak yapmamız gerekenler şunlardır:

// ES5 Fonksiyon Yapılandırıcısı function Student(name, studentId) { // Üst sınıfın yapılandırıcısını çağırarak üst sınıftan türetilmiş üyeleri başlatın. Person.call(this, name); // Alt sınıfın kendi üyelerini başlatın. this.studentId = studentId; } Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; // ES6 Sınıfı class Student extends Person { constructor(name, studentId) { super(name); this.studentId = studentId; } }

ES5'te kalıtım kullanmak çok daha ayrıntılıdır ve ES6 sürümü anlaşılması ve hatırlanması daha kolaydır.

Yeni ok => fonksiyon sözdizimi için bir kullanım durumu önerebilir misiniz? Bu yeni sözdizimi diğer fonksiyonlardan nasıl farklıdır?

Ok fonksiyonlarının belirgin bir faydası, function anahtar kelimesine ihtiyaç duymadan fonksiyonlar oluşturmak için gereken sözdizimini basitleştirmesidir. Ok fonksiyonları içindeki this de kapsayan kapsama bağlıdır, bu da this'in onu çağıran nesne tarafından belirlendiği normal fonksiyonlardan farklıdır. Sözcükbilimsel olarak kapsamlı this, özellikle React bileşenlerinde geri çağrıları çağırırken kullanışlıdır.

Bir yapılandırıcıda bir yöntem için ok sözdizimi kullanmanın ne gibi bir avantajı vardır?

Bir yapılandırıcının içinde bir yöntem olarak ok işlevi kullanmanın temel avantajı, this değerinin işlevin oluşturulduğu anda ayarlanması ve bundan sonra değişmemesidir. Böylece, yapılandırıcı yeni bir nesne oluşturmak için kullanıldığında, this her zaman o nesneye atıfta bulunacaktır. Örneğin, bir Person yapılandırıcımız olduğunu ve bunun bir ad argümanı aldığını ve o adı console.log'lamak için iki yöntemi olduğunu varsayalım, biri normal bir işlev olarak, diğeri ok işlevi olarak:

const Person = function (firstName) { this.firstName = firstName; this.sayName1 = function () { console.log(this.firstName); }; this.sayName2 = () => { console.log(this.firstName); }; }; const john = new Person('John'); const dave = new Person('Dave'); john.sayName1(); // John john.sayName2(); // John // Normal işlevin 'this' değeri değiştirilebilir, ancak ok işlevininki değiştirilemez john.sayName1.call(dave); // Dave (çünkü "this" artık dave nesnesi) john.sayName2.call(dave); // John john.sayName1.apply(dave); // Dave (çünkü 'this' artık dave nesnesi) john.sayName2.apply(dave); // John john.sayName1.bind(dave)(); // Dave (çünkü 'this' artık dave nesnesi) john.sayName2.bind(dave)(); // John var sayNameFromWindow1 = john.sayName1; sayNameFromWindow1(); // undefined (çünkü 'this' artık window nesnesi) var sayNameFromWindow2 = john.sayName2; sayNameFromWindow2(); // John

Buradaki ana çıkarım, normal bir işlev için this'in değiştirilebilmesidir, ancak ok işlevi için bağlam her zaman aynı kalır. Dolayısıyla, ok işlevinizi uygulamanızın farklı yerlerine iletiyor olsanız bile, bağlamın değişmesi konusunda endişelenmenize gerek kalmaz.

Bu, React sınıf bileşenlerinde özellikle yararlı olabilir. Bir tıklama işleyicisi gibi bir şey için normal bir işlev kullanarak bir sınıf yöntemi tanımlarsanız ve bu tıklama işleyicisini bir alt bileşene bir özellik olarak geçirirseniz, üst bileşenin yapılandırıcısında da this'i bağlamanız gerekir. Bunun yerine bir ok işlevi kullanırsanız, "this"'i bağlamaya gerek kalmaz, çünkü yöntem otomatik olarak "this" değerini kapsayan sözcüksel bağlamından alacaktır.

Üst düzey bir fonksiyonun tanımı nedir?

Üst düzey bir fonksiyon, bir veya daha fazla fonksiyonu argüman olarak alan, bu argümanları bazı veriler üzerinde işlem yapmak için kullanan ve/veya sonuç olarak bir fonksiyon döndüren herhangi bir fonksiyondur. Üst düzey fonksiyonlar, tekrar tekrar gerçekleştirilen bazı işlemleri soyutlamak için tasarlanmıştır. Bunun klasik örneği, bir dizi ve bir fonksiyonu argüman olarak alan map'tir. map daha sonra bu fonksiyonu dizideki her öğeyi dönüştürmek için kullanır ve dönüştürülmüş verilerle yeni bir dizi döndürür. JavaScript'teki diğer popüler örnekler forEach, filter ve reduce'dir. Üst düzey bir fonksiyonun sadece dizileri manipüle etmesi gerekmez, çünkü başka bir fonksiyondan bir fonksiyon döndürmek için birçok kullanım durumu vardır. Function.prototype.bind, JavaScript'teki böyle bir örnektir.

Haritala

Her bir dizeyi büyük harfe dönüştürmemiz gereken bir ad dizimiz olduğunu varsayalım.

const names = ['irish', 'daisy', 'anna'];

Zorunlu yol şöyle olacaktır:

const transformNamesToUppercase = function (names) { const results = []; for (let i = 0; i < names.length; i++) { results.push(names[i].toUpperCase()); } return results; }; transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

.map(transformerFn) kullanmak kodu daha kısa ve daha bildirimsel hale getirir.

const transformNamesToUppercase = function (names) { return names.map((name) => name.toUpperCase()); }; transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

Bir nesneyi veya bir diziyi yapı bozma için bir örnek verebilir misiniz?

Yapı bozma, ES6'da bulunan bir ifadedir ve Nesnelerin veya Dizilerin değerlerini çıkarıp ayrı değişkenlere yerleştirmek için özlü ve uygun bir yol sağlar.

Dizi yapı bozma

// Değişken ataması. const foo = ['one', 'two', 'three']; const [one, two, three] = foo; console.log(one); // "one" console.log(two); // "two" console.log(three); // "three"
// Değişkenleri değiştirme let a = 1; let b = 3; [a, b] = [b, a]; console.log(a); // 3 console.log(b); // 1

Nesne yapı bozma

// Değişken ataması. const o = { p: 42, q: true }; const { p, q } = o; console.log(p); // 42 console.log(q); // true

ES6 Şablon Değişmezleri dizeler oluşturmada çok fazla esneklik sunar, bir örnek verebilir misiniz?

Şablon değişmezleri, dize enterpolasyonunu veya bir dizeye değişkenleri dahil etmeyi basit hale getirmeye yardımcı olur. ES2015'ten önce, şöyle bir şey yapmak yaygındı:

var person = { name: 'Tyler', age: 28 }; console.log( 'Merhaba, benim adım ' + person.name + ' ve ben ' + person.age + ' yaşındayım!', ); // 'Merhaba, benim adım Tyler ve ben 28 yaşındayım!'

Şablon değişmezleri ile artık aynı çıktıyı şöyle oluşturabilirsiniz:

const person = { name: 'Tyler', age: 28 }; console.log(`Merhaba, benim adım ${person.name} ve ben ${person.age} yaşındayım!`); // 'Merhaba, benim adım Tyler ve ben 28 yaşındayım!'

Bir şablon değişmezi kullandığınızı belirtmek için tırnak işaretleri değil, ters tırnaklar kullandığınızı ve ${} yer tutucularının içine ifadeler ekleyebileceğinizi unutmayın.

İkinci yararlı bir kullanım durumu, çok satırlı dizeler oluşturmaktır. ES2015'ten önce, çok satırlı bir dizeyi şöyle oluşturabilirdiniz:

console.log('Bu birinci satır.\nBu ikinci satır.'); // Bu birinci satır. // Bu ikinci satır.

Veya kodunuzda birden çok satıra bölmek istiyorsanız, uzun bir dizeyi okumak için metin düzenleyicinizde sağa kaydırmanıza gerek kalmazdı, şöyle de yazabilirdiniz:

console.log('Bu birinci satır.\n' + 'Bu ikinci satır.'); // Bu birinci satır. // Bu ikinci satır.

Ancak, şablon değişmezleri, onlara eklediğiniz boşluğu korur. Örneğin, yukarıda oluşturduğumuz aynı çok satırlı çıktıyı oluşturmak için basitçe şöyle yapabilirsiniz:

console.log(`Bu birinci satır. Bu ikinci satır.`); // Bu birinci satır. // Bu ikinci satır.

Şablon değişmezlerinin başka bir kullanım durumu da, basit değişken enterpolasyonları için şablonlama kütüphanelerinin yerine kullanılması olacaktır:

const person = { name: 'Tyler', age: 28 }; document.body.innerHTML = ` <div> <p>Adı: ${person.name}</p> <p>Yaşı: ${person.age}</p> </div> `;

Kodunuzun .innerHTML kullanarak XSS'ye maruz kalabileceğini unutmayın. Veri bir kullanıcıdan geliyorsa, görüntülemeden önce dezenfekte edin!

Curry fonksiyonuna bir örnek ve bu sözdiziminin neden bir avantaj sunduğunu verebilir misiniz?

Currying, birden fazla parametreli bir fonksiyonun, seri olarak çağrıldığında gerekli tüm parametreleri tek tek biriktirecek birden çok fonksiyona bölünmesidir. Bu teknik, fonksiyonel stilde yazılmış kodun okunmasını ve birleştirilmesini kolaylaştırmak için kullanışlı olabilir. Bir fonksiyonun curried olması için, tek bir fonksiyon olarak başlaması, ardından her biri tek bir parametre kabul eden bir dizi fonksiyona ayrılması gerektiğini unutmamak önemlidir.

function curry(fn) { if (fn.length === 0) { return fn; } function _curried(depth, args) { return function (newArgument) { if (depth - 1 === 0) { return fn(...args, newArgument); } return _curried(depth - 1, [...args, newArgument]); }; } return _curried(fn.length, []); } function add(a, b) { return a + b; } var curriedAdd = curry(add); var addFive = curriedAdd(5); var result = [0, 1, 2, 3, 4, 5].map(addFive); // [5, 6, 7, 8, 9, 10]

Yayılma sözdizimi kullanmanın faydaları nelerdir ve kalan sözdiziminden farkı nedir?

ES6'nın yayılma sözdizimi, fonksiyonel bir paradigmada kodlama yaparken çok kullanışlıdır, çünkü Object.create, slice veya bir kütüphane fonksiyonuna başvurmadan dizilerin veya nesnelerin kopyalarını kolayca oluşturabiliriz. Bu dil özelliği Redux ve RxJS projelerinde sıklıkla kullanılır.

function putDookieInAnyArray(arr) { return [...arr, 'dookie']; } const result = putDookieInAnyArray(['I', 'really', "don't", 'like']); // ["I", "really", "don't", "like", "dookie"] const person = { name: 'Todd', age: 29, }; const copyOfTodd = { ...person };

ES6'nın kalan sözdizimi, bir fonksiyona geçirilecek rastgele sayıda argümanı dahil etmek için kısa bir yol sunar. Yayılma sözdiziminin tersi gibidir, verileri alır ve bir dizi veri açmak yerine bir diziye doldurur ve fonksiyon argümanlarında, ayrıca dizi ve nesne yapı bozma atamalarında çalışır.

function addFiveToABunchOfNumbers(...numbers) { return numbers.map((x) => x + 5); } const result = addFiveToABunchOfNumbers(4, 5, 6, 7, 8, 9, 10); // [9, 10, 11, 12, 13, 14, 15] const [a, b, ...rest] = [1, 2, 3, 4]; // a: 1, b: 2, rest: [3, 4] const { e, f, ...others } = { e: 1, f: 2, g: 3, h: 4, }; // e: 1, f: 2, others: { g: 3, h: 4 }

Dosyalar arasında kodu nasıl paylaşabilirsiniz?

Bu, JavaScript ortamına bağlıdır.

İstemci tarafında (tarayıcı ortamı), değişkenler/fonksiyonlar global kapsamda (window) bildirilmiş olduğu sürece, tüm betikler onlara referans verebilir. Alternatif olarak, daha modüler bir yaklaşım için RequireJS aracılığıyla Asenkron Modül Tanımını (AMD) benimseyin.

Sunucu tarafında (Node.js), yaygın yol CommonJS kullanmaktır. Her dosya bir modül olarak kabul edilir ve değişkenleri ve fonksiyonları module.exports nesnesine ekleyerek dışa aktarabilir.

ES2015, hem AMD hem de CommonJS'yi değiştirmeyi amaçlayan bir modül sözdizimi tanımlar. Bu sonunda hem tarayıcı hem de Node ortamlarında desteklenecektir.

Neden statik sınıf üyeleri oluşturmak isteyebilirsiniz?

Statik sınıf üyeleri (özellikler/yöntemler) bir sınıfın belirli bir örneğine bağlı değildir ve hangi örneğin ona başvurduğuna bakılmaksızın aynı değere sahiptirler. Statik özellikler tipik olarak yapılandırma değişkenleridir ve statik yöntemler genellikle örneğin durumuna bağlı olmayan saf yardımcı fonksiyonlardır.