我想知道-类方法,作为函数的类属性和作为箭头函数的类属性之间有什么区别?在不同的方法变体中,“ 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();
编辑:已编译的打字稿的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
答案 0 :(得分:2)
所有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个函数调用将按预期打印:'greet* me'
在bla
上调用
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
时,它们都需要分配一个新的闭包。
打字稿中的此类型是什么。
Typescript将在方法(this
)和箭头函数(Greeter
)中将greet
键入为greet2
的实例,但将键入this
与greet3
中的任何内容一样。如果您尝试在this
下的greet3
中使用noImplictAny
何时使用它们
如果该函数不会作为事件处理程序传递给另一个组件,请使用方法语法(除非您使用bind
或其他方式来确保this
仍是该类的实例)
当您的函数将被传递给其他组件并且您需要访问函数内部的this
时,请使用箭头函数语法。
为此,真的不能想到一个好的用例,通常避免使用。
答案 1 :(得分:1)
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
但是还有另一个区别,第一种方法在prototype
的{{1}}上,而其他两种不在。它们是对象实例的方法。
class
如果我在类->
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";
并输出“我的字符串”。但我想知道-这真的是同一件事
不,他们不是同一个人。正如我提到的,console.log(this.str)
和greet2
将不在greet3
上,而将在实例本身上。这意味着,如果您创建Greeter.prototype
的{{1}}个实例,它们将在内存中存储1000种不同方法(1000
和Greeter
),用于1000种不同实例。但是所有实例都只有一个greet2
方法。
请参见下面的摘录,其中包含两个greet3
实例