类方法与类字段函数与类字段箭头函数有什么区别? [英] What is the difference between class method vs. class field function vs. class field arrow function?

查看:28
本文介绍了类方法与类字段函数与类字段箭头函数有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类方法、作为函数的类属性和作为箭头函数的类属性有什么区别?this 关键字在方法的不同变体中的行为是否不同?

class Greeter {构造函数(){this.greet();this.greet2();this.greet3();}问候(){console.log('greet1', this);}问候2 = () =>{console.log('greet2', this);}问候3 =函数(){console.log('greet3', this);}}让 bla = new Greeter();

这是从 TypeScript 转译的结果 JavaScript.

var Greeter =/** @class */(function () {函数迎宾(){var _this = this;this.greet2 = 函数 () {console.log('greet2', _this);};this.greet3 = 函数 () {console.log('greet3', this);};this.greet();this.greet2();this.greet3();}Greeter.prototype.greet = 函数 () {console.log('greet1', this);};返回迎宾员;}());var bla = new Greeter();

我的 TypeScript 版本是 3.4.5.

解决方案

所有 3 个版本之间都存在差异.这种差异体现在 3 个方面:

  1. 运行时this是谁
  2. 分配函数的位置
  3. 打字稿中this的类型是什么.

让我们从它们工作的地方开始.考虑这个具有类字段的类:

class Greeter {构造函数(私有 x:字符串){}问候(){console.log('greet1', this.x);}问候2 = () =>{console.log('greet2', this.x);}问候3 =函数(){//这被输入为 anyconsole.log('greet3', this.x);}}let bla = new Greeter("我");

有了这个类,所有 3 个函数调用都会按预期打印:'greet* me' 当在 bla

上调用时

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

运行时是谁

箭头函数从声明上下文中捕获this,因此greet2 中的this 始终保证是创建此函数的类实例.其他版本(方法和函数)没有这样的保证.

所以在这段代码中,并非所有 3 个都打印相同的文本:

function call(fn: () => void) {fn();}call(bla.greet)//greet1 未定义call(bla.greet2)//向我问好call(bla.greet3)//greet3 未定义

这在将函数作为事件处理程序传递给另一个组件时尤为重要.

函数的分配位置

类方法(如greet)在原型上赋值,字段初始化(如greet2greet3)在原型上赋值构造函数.这意味着 greet2greet3 将有更大的内存占用,因为它们需要在每次 Greeter 实例化时分配一个新的闭包.>

打字稿中 this 的类型是什么.

Typescript 将在方法 (greet) 和箭头函数 (greet2) 但会像 greet3 中的 any 一样输入 this.如果您尝试在 noImplictAny

下的 greet3 中使用 this ,这将导致错误

何时使用它们

  1. 如果此函数不会作为事件处理程序传递给另一个组件,请使用方法语法(除非您使用 bind 或其他东西来确保 this 保持不变类的实例)

  2. 当您的函数将传递给其他组件并且您需要访问函数内部的this时,请使用箭头函数语法.

  3. 实在想不出一个好的用例,一般避免.

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?

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.

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.

解决方案

There are differences between all 3 versions. This differences are in 3 areas:

  1. Who is this at runtime
  2. Where the function is assigned
  3. What is the type of this in typescript.

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

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. The other versions (the method and function) make no such guarantees.

So in this code not all 3 print the same text:

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

What is the type of this in typescript.

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 will make it an error if you try to use this in greet3 under noImplictAny

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)

  2. Use arrow function syntax when your function will be passed around to other components and you need access to this inside the function.

  3. Can't really think of a good use case for this, generally avoid.

这篇关于类方法与类字段函数与类字段箭头函数有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆