简体   繁体   English

类方法与类字段函数与类字段箭头函数有什么区别?

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

What is the difference between class method, class property which is a function, and class property which is an arrow function?类方法、作为函数的类属性和作为箭头函数的类属性有什么区别? Does the this keyword behave differently in the different variants of the method? 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();

This is the resulting JavaScript when transpiled from TypeScript.这是从 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();

My TypeScript version is 3.4.5.我的 TypeScript 版本是 3.4.5。

There are differences between all 3 versions.所有 3 个版本之间都存在差异。 This differences are in 3 areas:这种差异体现在 3 个方面:

  1. Who is this at runtime运行时this是谁
  2. Where the function is assigned分配功能的地方
  3. What is the type of this in typescript.打字稿中this的类型是什么。

Lets start with where they work just the same.让我们从它们工作的地方开始。 Consider this class, with a class field:考虑这个具有类字段的类:

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

With this class all 3 function calls will print as expected: 'greet* me' when invoked on bla有了这个类,所有 3 个函数调用都将按预期打印:在bla调用时, 'greet* me'

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

Who is this at runtime运行时这是谁

Arrow functions capture this from the declaration context, so this in greet2 is always guaranteed to be the class instance that created this function.箭头功能捕捉this从声明上下文,所以thisgreet2始终保证是创建此函数的类的实例。 The other versions (the method and function) make no such guarantees.其他版本(方法和函数)没有这样的保证。

So in this code not all 3 print the same text:因此,在此代码中,并非所有 3 个都打印相同的文本:

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

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

This is particularly important when passing the function as an event handler to another component.这在将函数作为事件处理程序传递给另一个组件时尤为重要。

Where the function is assigned分配功能的地方

Class methods (such as greet ) are assigned on the prototype, field initializations (such as greet2 and greet3 ) are assigned in the constructor.类方法(如greet )在原型上赋值,字段初始化(如greet2greet3 )在构造函数中赋值。 This means that greet2 and greet3 will have a larger memory footprint as they require an allocation of a fresh closure each time Greeter is instantiated.这意味着greet2greet3将有更大的内存占用,因为它们需要在每次Greeter实例化时分配一个新的闭包。

What is the type of this in typescript.打字稿中 this 的类型是什么。

Typescript will type this as an instance of Greeter in both the method ( greet ) and the arrow function ( greet2 ) but will type this as any in greet3 .打字稿将键入this作为实例Greeter在方法(两者greet )和箭头功能( greet2 ),但将输入this作为任何在greet3 This will make it an error if you try to use this in greet3 under noImplictAny这将使一个错误,如果你尝试使用thisgreet3noImplictAny

When to use them何时使用它们

  1. Use the method syntax if this function will not be passed as an event handler to another component (unless you use bind or something else to ensure this remains the instance of the class)如果此函数不会作为事件处理程序传递给另一个组件,请使用方法语法(除非您使用bind或其他方法来确保this仍然是类的实例)

  2. Use arrow function syntax when your function will be passed around to other components and you need access to this inside the function.当您的函数将传递给其他组件并且您需要在函数内部访问this时,请使用箭头函数语法。

  3. Can't really think of a good use case for this, generally avoid.真的想不出一个好的用例,一般避免。

this keyword difference: this关键字区别:

In the above all three have same this but you will see the difference when you will pass the method to another functions.在上面所有三个都有相同的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

But there is another difference that the first method is on the prototype of class while other two are not.但是还有一个区别,第一个方法在classprototype ,而其他两个不在。 They are the method of instance of object.它们是对象实例的方法。

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

If I have in the class -> str = "my string";如果我在课堂上 -> str = "my string"; and in all the 3 methods I can say console.log(this.str) and it outputs the "my string".在所有 3 种方法中,我都可以说console.log(this.str)并输出“我的字符串”。 But I wonder - is this really actually the same thing但我想知道 - 这真的是同一件事吗

No they are not same things.不,它们不是同一回事。 As I mentioned that greet2 and greet3 will not be on Greeter.prototype instead they will be on the instance itself.正如我提到的, greet2greet3不会在Greeter.prototype而是在实例本身上。 It mean that if you create 1000 instances of Greeter their will be 1000 different method( greet2 and greet3 ) stored in memory for 1000 different instances.这意味着如果你创建1000 Greeter实例,它们将有 1000 个不同的方法( greet2greet3 )存储在内存中,用于 1000 个不同的实例。 But there will a single greet method for all the instances.但是所有实例都有一个greet方法。

See the below snippet with two instances of Greeter()请参阅下面的代码片段,其中包含两个Greeter()实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM