![](/img/trans.png)
[英]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.