Skip to content

Instantly share code, notes, and snippets.

@cemtopkaya
Created December 22, 2024 09:47
Show Gist options
  • Save cemtopkaya/e1a7473e784fb949d4d4740bbba4caa9 to your computer and use it in GitHub Desktop.
Save cemtopkaya/e1a7473e784fb949d4d4740bbba4caa9 to your computer and use it in GitHub Desktop.
Javascript ve nodejs soruları
@cemtopkaya
Copy link
Author

cemtopkaya commented Dec 22, 2024

Soru:

Aşağıdaki kod parçacığını inceleyin ve soruları cevaplayın:

const obj = {
  name: "JavaScript",
  regularFunction: function () {
    console.log("1:", this.name);
    const innerFunction = function () {
      console.log("2:", this.name);
    };
    innerFunction();
  },
  arrowFunction: () => {
    console.log("3:", this.name);
    const innerArrow = () => {
      console.log("4:", this.name);
    };
    innerArrow();
  },
};

function globalFunction() {
  console.log("5:", this.name);
}

const outerFunction = function () {
  console.log("6:", this.name);
  const nestedFunction = function () {
    console.log("7:", this.name);
  };
  const nestedArrow = () => {
    console.log("8:", this.name);
  };
  nestedFunction();
  nestedArrow();
};

obj.regularFunction();
obj.arrowFunction();
globalFunction();
outerFunction.call({ name: "Outer Context" });

Sorular:

  1. Kod çalıştırıldığında her bir console.log satırı neyi yazdırır? Neden?
  2. regularFunction içinde tanımlanan innerFunction hangi this bağlamını kullanır? Buna erişmek için nasıl bir çözüm uygulayabilirsiniz?
  3. arrowFunction içinde this bağlamı neden obj'i göstermez? Bu bağlamı değiştirmek mümkün müdür?
  4. outerFunction ve içindeki nestedFunction ile nestedArrow'un bağlamları nasıl farklıdır? İkisinin farkını açıklayın.
  5. call yöntemi kullanılarak outerFunction'un bağlamı değiştirildiğinde nestedFunction ve nestedArrow bu bağlamı nasıl etkiler?
  6. Bonus: Bu kodda this bağlamını değiştirmek için bind, call, veya apply yöntemlerinden herhangi birini kullanmadan regularFunction ve innerFunction'u bağlamlarını paylaşacak şekilde yeniden yazabilir misiniz?

Beklenen Cevaplar:

  1. console.log Çıktıları
1: JavaScript
2: 
3: 
4: 
5: 
6: Outer Context
7: 
8: Outer Context

Bu sorular adayın:

  • Scope (blok, fonksiyon, ve global) ve closure kavramlarını,
  • this bağlamını ve nasıl değiştirilebileceğini,
  • Lambda (ok fonksiyonları) ve klasik fonksiyonlar arasındaki farkları,
  • call, apply, ve bind gibi yöntemleri nasıl kullandığını,
  • JavaScript'in execution context mekanizmasını ne kadar derinlemesine anladığını ölçmek için tasarlanmıştır.

Örnek Tartışma Konuları:

  • Aday innerFunction için bir çözüm olarak self = this veya bind yöntemini öneriyorsa, bunun avantajlarını ve dezavantajlarını tartışabilirsiniz.
  • Ok fonksiyonlarının lexical this özelliği bağlamında, adayın nasıl açıklama yaptığına dikkat edin.

Biraz fikirleşelim:

JavaScript'te this anahtar kelimesinin bağlamı, fonksiyonun nasıl çağrıldığına bağlıdır. Yukarıdaki kodda regularFunction içinde tanımlanan innerFunction, kendi bağlamında çağrıldığında this anahtar kelimesi, global nesneye (tarayıcıda window, Node.js'te global) referans eder. Bu nedenle, innerFunction içinde this.name ifadesi, global bağlamda tanımlı bir name değişkenine erişmeye çalışır.

Çözüm Yöntemleri

innerFunction'ın doğru this bağlamını kullanmasını sağlamak için birkaç farklı yaklaşım bulunmaktadır:

1. bind Metodu Kullanımı

innerFunction'ı çağırmadan önce bind metodu ile doğru bağlamı belirleyebilirsiniz:

const obj = {
  name: "JavaScript",
  regularFunction: function () {
    console.log("1:", this.name);
    const innerFunction = function () {
      console.log("2:", this.name);
    }.bind(this); // 'this' burada obj'yi referans alır
    innerFunction();
  },
  // Diğer kodlar...
};

obj.regularFunction(); // Çıktı: "1: JavaScript" ve "2: JavaScript"

2. Arrow Function Kullanımı

Arrow function'lar, tanımlandıkları bağlamın this değerini korur. Bu yüzden innerFunction yerine bir arrow function kullanabilirsiniz:

const obj = {
  name: "JavaScript",
  regularFunction: function () {
    console.log("1:", this.name);
    const innerFunction = () => {
      console.log("2:", this.name); // 'this' burada obj'yi referans alır
    };
    innerFunction();
  },
  // Diğer kodlar...
};

obj.regularFunction(); // Çıktı: "1: JavaScript" ve "2: JavaScript"

3. Değişken Tanımlama ile Erişim

Fonksiyonun başında this değerini bir değişkene atayarak da erişebilirsiniz:

const obj = {
  name: "JavaScript",
  regularFunction: function () {
    console.log("1:", this.name);
    const self = this; // 'this' değerini self değişkenine atıyoruz
    const innerFunction = function () {
      console.log("2:", self.name); // 'self' ile obj'ye erişiyoruz
    };
    innerFunction();
  },
  // Diğer kodlar...
};

obj.regularFunction(); // Çıktı: "1: JavaScript" ve "2: JavaScript"

Sonuç

Bu yöntemlerden herhangi biri, innerFunction içinde doğru this bağlamını kullanarak istenen sonucu elde etmenizi sağlar. Arrow function kullanmak genellikle en temiz ve okunabilir çözüm olarak tercih edilir.

@cemtopkaya
Copy link
Author

Soru:

Aşağıdaki kod parçacığını inceleyin ve ilgili soruları cevaplayın:

function Timer() {
  this.seconds = 0;

  // Arrow function ile tanımlı bir interval
  this.startArrow = function () {
    setInterval(() => {
      this.seconds++;
      console.log("Arrow:", this.seconds);
    }, 1000);
  };

  // Klasik function ile tanımlı bir interval
  this.startRegular = function () {
    setInterval(function () {
      this.seconds++;
      console.log("Regular:", this.seconds);
    }, 1000);
  };

  // self ile çözüm denemesi
  this.startWithSelf = function () {
    const self = this;
    setInterval(function () {
      self.seconds++;
      console.log("Self:", self.seconds);
    }, 1000);
  };
}

// Timer nesnesini başlat ve fonksiyonları sırayla çalıştır
const timer = new Timer();
timer.startArrow();
timer.startRegular();
setTimeout(() => {
  timer.startWithSelf();
}, 3000);

Sorular:

  1. startArrow, startRegular, ve startWithSelf fonksiyonları arasındaki farklar nelerdir? Çıktılar nasıl olur?
  2. this bağlamı startRegular fonksiyonunda neden beklenildiği gibi çalışmaz? Bunun çözümü için bind yöntemini nasıl kullanabilirsiniz?
  3. self değişkeni hangi durumda gerekli olur ve neden işe yarar? JavaScript'in this bağlamı ile self arasındaki farkı açıklayın.
  4. Bonus: startWithSelf fonksiyonunu self kullanmadan, modern ES6+ yöntemlerini kullanarak yeniden yazabilir misiniz?

Beklenen Cevaplar:

1. Çıktı Analizi:

Kod çalıştırıldığında aşağıdaki çıktılar oluşacaktır:

  • startArrow: Arrow fonksiyonu this bağlamını lexical (tanımlandığı yerin bağlamı) olarak kullanır. Yani, this burada Timer nesnesini işaret eder ve seconds artışını doğru şekilde yapar. Örnek çıktı:

    Arrow: 1
    Arrow: 2
    Arrow: 3
    
  • startRegular: Klasik fonksiyon this bağlamını runtime'da belirler. Burada setInterval global bir fonksiyon olduğu için this undefined (strict mode) veya window (non-strict mode) olur. Dolayısıyla this.seconds artırılamaz ve hata alabilirsiniz. Örnek çıktı:

    Uncaught TypeError: Cannot read properties of undefined (reading 'seconds')
    
  • startWithSelf: self değişkeni dıştaki fonksiyonun this bağlamını tutar ve içeride erişilebilir hale getirir. Bu, Timer nesnesinin seconds değerini artırmayı sağlar. Örnek çıktı:

    Self: 1
    Self: 2
    Self: 3
    

2. this Bağlamı ve startRegular:

startRegular fonksiyonundaki this sorunu bind kullanılarak çözülebilir:

this.startRegular = function () {
  setInterval(function () {
    this.seconds++;
    console.log("Regular with bind:", this.seconds);
  }.bind(this), 1000);
};

Bu çözümde bind(this) ifadesi, setInterval'in callback'inin this bağlamını Timer nesnesine sabitler.


3. self Kullanımının Gerekliliği:

self değişkeni, ES6 öncesi dönemde this bağlamının kaybolmasını önlemek için yaygın bir çözümdü. ES6+ ile arrow fonksiyonlar bu ihtiyacı büyük ölçüde ortadan kaldırdı. Ancak, arrow fonksiyon kullanılamadığı durumlarda (örneğin, eski tarayıcı desteği gerekirse) self hâlâ geçerli bir çözümdür.


4. Modern ES6+ ile Yeniden Yazım:

startWithSelf fonksiyonu modern bir arrow fonksiyon ile şu şekilde yeniden yazılabilir:

this.startWithSelf = function () {
  setInterval(() => {
    this.seconds++;
    console.log("Modern Self (Arrow):", this.seconds);
  }, 1000);
};

Bu yöntem hem okunabilirliği artırır hem de this bağlamını doğru şekilde işler.


Görüşme Yapan İçin Değerlendirme:

Adayın bu soruyu yanıtlarken şu konulara hakimiyetini değerlendiriniz:

  • this bağlamını anlaması ve farklı bağlamlarda nasıl değiştiğini açıklayabilmesi.
  • Klasik fonksiyonlar ile arrow fonksiyonlar arasındaki farkları net şekilde ifade edebilmesi.
  • self gibi eski yöntemlerin ne zaman gerekli olduğunu ve modern alternatiflerini açıklayabilmesi.
  • JavaScript'in execution context mantığını derinlemesine kavrayıp kavrayamadığı.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment