javascript - Sınıf yöntemi ile sınıf alanı fonksiyonu ile sınıf alanı ok fonksiyonu arasındaki fark nedir?


Sınıf metodu, fonksiyon olan sınıf özelliği ve ok fonksiyonu olan sınıf özelliği arasındaki fark nedir? this anahtar kelimesi metodun farklı türlerinde farklı mı davranır?

class Greeter {
  constructor() {
    this.greet();
    this.greet2();
    this.greet3();
  }

  greet() {
    console.log('greet1', this);
  }

  greet2 = () => {
    console.log('greet2', this);
  }

  greet3 = function() {
    console.log('greet3', this);
  }
}
      
let bla = new Greeter();

Bu, TypeScript'ten çevrildiğinde ortaya çıkan JavaScript'tir.

var Greeter = /** @class */ (function () {
function Greeter() {
    var _this = this;
    this.greet2 = function () {
        console.log('greet2', _this);
    };
    this.greet3 = function () {
        console.log('greet3', this);
    };
    this.greet();
    this.greet2();
    this.greet3();
}
Greeter.prototype.greet = function () {
    console.log('greet1', this);
};
return Greeter;
}());
var bla = new Greeter();

Benim TypeScript sürümüm 3.4.5.

Cevap #1

Üç sürüm arasında farklar vardır. Bu farklar 3 alanda bulunmaktadır:

  1. Çalışma zamanında bu kimdir
  2. Fonksiyonun atandığı yer
  3. Typescript'te this türü nedir.

Hadi işe nerede aynı şekilde çalıştıklarından başlayalım. Şuna bakın, bir sınıf ve sınıf alanı ile:

class Greeter {
  constructor(private x: string) {
  }
  greet() {
    console.log('greet1', this.x);
  }

  greet2 = () => {
    console.log('greet2', this.x);
  }

  greet3 = function () {    
    // this is typed as any 
    console.log('greet3', this.x);
  }
}

let bla = new Greeter(" me");

Bu sınıf ile tüm 3 fonksiyon çağrısı beklendiği gibi yazdırılacaktır: 'greet* me', bla üzerinde çağrıldığında

bla.greet()
bla.greet2()
bla.greet3()

Çalışma zamanında bu kim

Ok fonksiyonları this'i bildirim bağlamından yakalar, bu yüzden greet2'deki this her zaman bu fonksiyonu oluşturan sınıf örneği olacağı garanti edilir. Diğer sürümler (yöntem ve fonksiyon) böyle bir garanti vermez.

Yani bu kodda üçü de aynı metni yazdırmıyor:

function call(fn: () => void) {
  fn();
}

call(bla.greet) // greet1 undefined 
call(bla.greet2) //greet2 me
call(bla.greet3) // greet3 undefined

Bu, özellikle bir fonksiyonu başka bir bileşene olay işleyici olarak aktarırken önemlidir.

Fonksiyonun atandığı yer

Sınıf yöntemleri (örneğin greet) prototipe atanır, alan başlatmaları (örneğin greet2 ve greet3) yapıcıda atanır. Bu, greet2 ve greet3'ün daha büyük bir bellek alanına sahip olacağı anlamına gelir, çünkü her Greeter örneklendiğinde yeni bir kapanış ayrılmasını gerektirir.

Typescript'te bunun tipi nedir.

Typescript, hem metodda (greet) hem de ok fonksiyonunda (greet2) this'i Greeter örneği olarak tipler, ancak greet3'te this'i any olarak tipler. Bu, noImplicitAny altında greet3'te this'i kullanmaya çalışırsanız bir hata oluşturur.

Ne zaman kullanılır

  1. Bu işlev başka bir bileşenin olay işleyicisine aktarılmayacaksa yöntem sözdizimini kullanın (yoksa this sınıfın örneği olarak kalmasını sağlamak için bind veya başka bir şey kullanmadığınız sürece)

  2. Fonksiyonunuz başka bileşenlere aktarılacaksa ve fonksiyon içinde this'e erişmeniz gerekiyorsa ok fonksiyonu sözdizimini kullanın.

  3. Bunun için gerçekten iyi bir kullanım alanı düşünemiyorum, genellikle kaçınırım.

Cevap #2

this anahtar kelimesi farkı:

Yukarıdaki üçü de aynı this'e sahip, ancak metodu başka fonksiyonlara geçirdiğinizde farkı göreceksiniz.

class Greeter {
  constructor() {
  }
  greet() {
    console.log(this);
  }

  greet2 = () => {
    console.log(this);
  }

  greet3 = function() {
    console.log(this);
  }
}


let bla = new Greeter();
function wrapper(f){
  f();
}
wrapper(bla.greet) //undefined
wrapper(bla.greet2) //Greeter 
wrapper(bla.greet3) //undefined

Ama başka bir fark daha var: Birinci yöntem class'ın prototype'unda iken diğer ikisi değildir. Onlar nesnenin örneğinin yöntemleridir.

class Greeter {
  constructor() {
  }
  greet() {
    console.log('greet1', this);
  }

  greet2 = () => {
    console.log('greet2', this);
  }

  greet3 = function() {
    console.log('greet3', this);
  }
}

let bla = new Greeter();
console.log(Object.getOwnPropertyNames(Greeter.prototype))

Sınıfta şunu yaparsam -> str="my string"; ve üç yöntemin hepsinde console.log(this.str) diyebiliyorsam ve çıktısı "my string" oluyorsa. Ama merak ediyorum - gerçekten bu aynı şey mi?

Hayır, onlar aynı şeyler değiller. Daha önce belirttiğim gibi, greet2 ve greet3 Greeter.prototype üzerinde olmayacak, bunun yerine kendileri örneğin üzerinde olacak. Bu, eğer Greeter'dan 1000 örnek oluşturursanız, bellek üzerinde 1000 farklı örnek için 1000 farklı metoda (greet2 ve greet3) sahip olmanız anlamına gelir. Ama tüm örnekler için tek bir greet metodu olacaktır.

Aşağıdaki snippet'te iki tane Greeter() örneğini görün

İlgili makaleler