簡體   English   中英

類方法與類字段函數與類字段箭頭函數有什么區別?

[英]What is the difference between class method vs. class field function vs. class field arrow function?

類方法、作為函數的類屬性和作為箭頭函數的類屬性有什么區別? this關鍵字在方法的不同變體中的行為是否不同?

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();

這是從 TypeScript 轉譯的結果 JavaScript。

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();

我的 TypeScript 版本是 3.4.5。

所有 3 個版本之間都存在差異。 這種差異體現在 3 個方面:

  1. 運行時this是誰
  2. 分配功能的地方
  3. 打字稿中this的類型是什么。

讓我們從它們工作的地方開始。 考慮這個具有類字段的類:

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");

有了這個類,所有 3 個函數調用都將按預期打印:在bla調用時, 'greet* me'

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

運行時這是誰

箭頭功能捕捉this從聲明上下文,所以thisgreet2始終保證是創建此函數的類的實例。 其他版本(方法和函數)沒有這樣的保證。

因此,在此代碼中,並非所有 3 個都打印相同的文本:

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

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

這在將函數作為事件處理程序傳遞給另一個組件時尤為重要。

分配功能的地方

類方法(如greet )在原型上賦值,字段初始化(如greet2greet3 )在構造函數中賦值。 這意味着greet2greet3將有更大的內存占用,因為它們需要在每次Greeter實例化時分配一個新的閉包。

打字稿中 this 的類型是什么。

打字稿將鍵入this作為實例Greeter在方法(兩者greet )和箭頭功能( greet2 ),但將輸入this作為任何在greet3 這將使一個錯誤,如果你嘗試使用thisgreet3noImplictAny

何時使用它們

  1. 如果此函數不會作為事件處理程序傳遞給另一個組件,請使用方法語法(除非您使用bind或其他方法來確保this仍然是類的實例)

  2. 當您的函數將傳遞給其他組件並且您需要在函數內部訪問this時,請使用箭頭函數語法。

  3. 真的想不出一個好的用例,一般避免。

this關鍵字區別:

在上面所有三個都有相同的this但是當你將方法傳遞給另一個函數時你會看到不同。

 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

但是還有一個區別,第一個方法在classprototype ,而其他兩個不在。 它們是對象實例的方法。

 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))

如果我在課堂上 -> str = "my string"; 在所有 3 種方法中,我都可以說console.log(this.str)並輸出“我的字符串”。 但我想知道 - 這真的是同一件事嗎

不,它們不是同一回事。 正如我提到的, greet2greet3不會在Greeter.prototype而是在實例本身上。 這意味着如果你創建1000 Greeter實例,它們將有 1000 個不同的方法( greet2greet3 )存儲在內存中,用於 1000 個不同的實例。 但是所有實例都有一個greet方法。

請參閱下面的代碼片段,其中包含兩個Greeter()實例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM