[英]Calling regular function vs. arrow function before their declaration in a class
[英]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 個方面:
this
是誰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
從聲明上下文,所以this
在greet2
始終保證是創建此函數的類的實例。 其他版本(方法和函數)沒有這樣的保證。
因此,在此代碼中,並非所有 3 個都打印相同的文本:
function call(fn: () => void) {
fn();
}
call(bla.greet) // greet1 undefined
call(bla.greet2) //greet2 me
call(bla.greet3) // greet3 undefined
這在將函數作為事件處理程序傳遞給另一個組件時尤為重要。
分配功能的地方
類方法(如greet
)在原型上賦值,字段初始化(如greet2
和greet3
)在構造函數中賦值。 這意味着greet2
和greet3
將有更大的內存占用,因為它們需要在每次Greeter
實例化時分配一個新的閉包。
打字稿中 this 的類型是什么。
打字稿將鍵入this
作為實例Greeter
在方法(兩者greet
)和箭頭功能( greet2
),但將輸入this
作為任何在greet3
。 這將使一個錯誤,如果你嘗試使用this
在greet3
下noImplictAny
何時使用它們
如果此函數不會作為事件處理程序傳遞給另一個組件,請使用方法語法(除非您使用bind
或其他方法來確保this
仍然是類的實例)
當您的函數將傳遞給其他組件並且您需要在函數內部訪問this
時,請使用箭頭函數語法。
真的想不出一個好的用例,一般避免。
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
但是還有一個區別,第一個方法在class
的prototype
,而其他兩個不在。 它們是對象實例的方法。
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)
並輸出“我的字符串”。 但我想知道 - 這真的是同一件事嗎
不,它們不是同一回事。 正如我提到的, greet2
和greet3
不會在Greeter.prototype
而是在實例本身上。 這意味着如果你創建1000
Greeter
實例,它們將有 1000 個不同的方法( greet2
和greet3
)存儲在內存中,用於 1000 個不同的實例。 但是所有實例都有一個greet
方法。
請參閱下面的代碼片段,其中包含兩個Greeter()
實例
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.