什么时候应该在ECMAScript 6中使用箭头函数? [英] When should I use Arrow functions in ECMAScript 6?

查看:123
本文介绍了什么时候应该在ECMAScript 6中使用箭头函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题是针对即将到来的ECMAScript 6(Harmony)和已经使用该语言的人们已经考虑过代码风格的人。



使用()=> {} function(){} 我们得到两种非常类似的方法来在ES6中编写函数。在其他语言中,lambda函数通常通过匿名来区分自己,但是在ECMAScript中,任何函数都可以是匿名的。这两种类型中的每一种都具有唯一的使用域(即当 需要明确绑定或明确绑定时)。在这些域之间,有大量的符号可以做。



ES6中的箭头功能至少有两个限制:




  • 不适用

  • 修正这个在初始化时绑定到范围



除了这两个限制之外,箭头函数理论上可以替代任何地方的常规函数。在实践中使用它们的正确方法是什么?应该使用箭头功能,例如:




  • 无处不在,即无处不在的功能不必与这个变量,我们没有创建一个对象。

  • 只有需要的地方,即事件监听器,超时,需要绑定只有具有不包含另一个箭头函数的函数

  • 带有'short'功能,但不包含'long'函数




我正在寻找的是在未来版本的ECMAScript中选择适当的功能符号的指南。该指南将需要清楚,以便可以向团队中的开发人员讲授,并且要保持一致,从而不需要从一个功能符号到另一个功能符号来回重复。


之前,我们的团队将其所有代码(中型AngularJS应用程序)迁移到使用 Traceur编译的JavaScript中 Babel 。我现在使用以下ES6及更高版本中的函数经验法则:




  • 使用函数在全局范围内,对于 Object.prototype 属性。

  • 使用 class 对象构造函数。

  • 在其他地方使用 =>



为什么几乎无处不在使用箭头函数?


  1. 范围安全性:当一致使用箭头功能时一切都保证使用相同的 thisObject 作为根。如果即使单个标准函数回调与一堆箭头函数混合,也有可能会使范围变得混乱。

  2. 紧凑性:箭头函数更易于阅读和写入。 (这可能看起来很有意思,所以我会举一些例子)。

  3. 清晰度:几乎所有的东西都是一个箭头函数,任何常规的函数立即伸出来定义范围。开发人员可以随时查找下一个更高的函数语句,以查看 thisObject 是什么。

为什么总是在全局范围或模块范围使用常规函数?


  1. 要指示不应访问 thisObject 的函数。

  2. 窗口 object(global scope)最好明确地解决。

  3. 许多 Object.prototype 定义存在于全局范围内(认为 String.prototype.truncate 等),而且这些通常必须是函数的类型。一致地在全局范围内使用函数有助于避免错误。

  4. 全局范围中的许多函数是旧式类定义的对象构造函数

  5. 函数可以命名为 1 。这有两个好处:(1)写 function foo(){} const foo =()=>更不方便{} - 特别是在其他函数调用之外。 (2)功能名称显示在堆栈轨迹中。尽管命名所有内部回调是很麻烦的,但命名所有的公共函数可能是一个好主意。

  6. 函数声明是 hoisted (意思是在声明之前可以访问它们)这是静态效用函数中的一个有用的属性。



对象构造函数



尝试实例化箭头函数会抛出异常:

  var x =()=> {}; 
new x(); // TypeError:x不是构造函数

功能与箭头函数的一个关键优点是功能双作为对象构造函数:

  function Person(name){
this.name = name;
}

然而,功能上相同的 2 ES Harmony <一个href =http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes =noreferrer>草案类定义几乎相同:

  class Person {
constructor(name){
this.name = name;
}
}

我希望使用前面的符号最终会灰心。对象构造器符号可能仍然被一些用于简单的匿名对象工厂使用,其中对象以编程方式生成,但不是其他的。



需要一个对象构造函数考虑将函数转换为,如上所示。该语法与匿名函数/类一起使用。





箭头函数的可读性



坚持使用常规功能的最佳参数 - 范围安全性可能会导致箭头功能比常规功能的可读性差。如果你的代码首先没有起作用,那么箭头函数可能不是必需的,当箭头函数不一致地使用时,它们看起来很丑陋。



ECMAScript已经改变了有一点,因为ECMAScript 5.1给了我们功能 Array.forEach Array.map 和所有这些功能编程功能让我们使用以前使用for-loop的功能。异步JavaScript已经起飞了不少。 ES6还将发送一个 Promise 对象,这意味着更多的匿名函数。函数式编程没有必要。在功能性JavaScript中,箭头函数优于常规函数。



以此为例(特别令人困惑)代码 3

  function CommentController(articles){
this.comments = [];

articles.getList()
.then(articles => Promise.all(articles.map(article => article.comments.getList())))
.then(commentLists => commentLists.reduce((a,b)=> a.concat(b)));
.then(comments => {
this.comments = comments;
})
}

具有常规功能的同一段代码:

  function CommentController(articles) {
this.comments = [];

articles.getList()
.then(function(articles){
return Promise.all(articles.map(function(article)){
return article。 (
})
.then(function(commentLists){
return commentLists.reduce(function(a,b){
return a.concat(b);
});
})
.then(function(comments){
this.comments = comments;
} .bind(本));
}

虽然任何一个箭头功能都可以被标准功能所替代,这样做很少会获益。哪个版本更可读?我会说第一个。



我认为使用箭头功能或常规功能的问题将随着时间的推移变得越来越不相关。大多数函数将成为类方法,它们与函数关键字相脱离,否则将成为类。通过 Object.prototype ,函数将继续用于修补类。同时,我建议将函数关键字保留为真正是类方法或类的任何东西。






注意


  1. 命名的箭头功能已经延迟在ES6规格

  2. 根据草案规范类声明/表达式创建与函数声明完全相同的构造函数/原型对只要一个类不使用 extend 关键字。一个小的区别是类声明是常量,而函数声明不是。

  3. 注意单声明箭头函数中的块:我喜欢使用一个块来调用箭头函数单独的副作用(例如分配)。这样很清楚返回值可以被丢弃。


The question is directed at people who have thought about code style in the context of the upcoming ECMAScript 6 (Harmony) and who have already worked with the language.

With () => {} and function () {} we are getting two very similar ways to write functions in ES6. In other languages lambda functions often distinguish themselves by being anonymous, but in ECMAScript any function can be anonymous. Each of the two types have unique usage domains (namely when this needs to either be bound explicitly or explicitly not be bound). Between those domains there is a vast number of cases where either notation will do.

Arrow functions in ES6 have at least two limitations:

  • Don't work with new
  • Fixed this bound to scope at initialisation

These two limitations aside, arrow functions could theoretically replace regular functions almost anywhere. What is the right approach using them in practice? Should arrow functions be used e.g.:

  • "everywhere they work", i.e. everywhere a function does not have to be agnostic about the this variable and we are not creating an object.
  • only "everywhere they are needed", i.e. event listeners, timeouts, that need to be bound to a certain scope
  • with 'short' functions but not with 'long' functions
  • only with functions that do not contain another arrow function

What I am looking for is a guideline to selecting the appropriate function notation in the future version of ECMAScript. The guideline will need to be clear, so that it can be taught to developers in a team, and to be consistent so that it does not require constant refactoring back and forth from one function notation to another.

解决方案

A while ago our team migrated all its code (a mid-sized AngularJS app) to JavaScript compiled using Traceur Babel. I'm now using the following rule of thumb for functions in ES6 and beyond:

  • Use function in the global scope and for Object.prototype properties.
  • Use class for object constructors.
  • Use => everywhere else.

Why use arrow functions almost everywhere?

  1. Scope safety: When arrow functions are used consistently, everything is guaranteed to use the same thisObject as the root. If even a single standard function callback is mixed in with a bunch of arrow functions there's a chance the scope will become messed up.
  2. Compactness: Arrow functions are easier to read and write. (This may seem opinionated so I will give a few examples further on).
  3. Clarity: When almost everything is an arrow function, any regular function immediately sticks out for defining the scope. A developer can always look up the next-higher function statement to see what the thisObject is.

Why always use regular functions on the global scope or module scope?

  1. To indicate a function that should not access the thisObject.
  2. The window object (global scope) is best addressed explicitly.
  3. Many Object.prototype definitions live in the global scope (think String.prototype.truncate etc.) and those generally have to be of type function anyway. Consistently using function on the global scope helps avoid errors.
  4. Many functions in the global scope are object constructors for old-style class definitions.
  5. Functions can be named1. This has two benefits: (1) It is less awkward to writefunction foo(){} than const foo = () => {} — in particular outside other function calls. (2) The function name shows in stack traces. While it would be tedious to name every internal callback, naming all the public functions is probably a good idea.
  6. Function declarations are hoisted, (meaning they can be accessed before they are declared), which is a useful attribute in a static utility function.


Object constructors

Attempting to instantiate an arrow function throws an exception:

var x = () => {};
new x(); // TypeError: x is not a constructor

One key advantage of functions over arrow functions is therefore that functions double as object constructors:

function Person(name) {
    this.name = name;
}

However, the functionally identical2 ES Harmony draft class definition is almost as compact:

class Person {
    constructor(name) {
        this.name = name;
    }
}

I expect that use of the former notation will eventually be discouraged. The object constructor notation may still be used by some for simple anonymous object factories where objects are programmatically generated, but not for much else.

Where an object constructor is needed one should consider converting the function to a class as shown above. The syntax works with anonymous functions/classes as well.


Readability of arrow functions

The probably best argument for sticking to regular functions - scope safety be damned - would be that arrow functions are less readable than regular functions. If your code is not functional in the first place, then arrow functions may not seem necessary, and when arrow functions are not used consistently they look ugly.

ECMAScript has changed quite a bit since ECMAScript 5.1 gave us the functional Array.forEach, Array.map and all of these functional programming features that have us use functions where for-loops would have been used before. Asynchronous JavaScript has taken off quite a bit. ES6 will also ship a Promise object, which means even more anonymous functions. There is no going back for functional programming. In functional JavaScript, arrow functions are preferable over regular functions.

Take for instance this (particularly confusing) piece of code3:

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(articles => Promise.all(articles.map(article => article.comments.getList())))
        .then(commentLists => commentLists.reduce((a, b) => a.concat(b)));
        .then(comments => {
            this.comments = comments;
        })
}

The same piece of code with regular functions:

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(function (articles) {
            return Promise.all(articles.map(function (article) { 
                return article.comments.getList();
            }));
        })
        .then(function (commentLists) {
            return commentLists.reduce(function (a, b) {
                return a.concat(b); 
            });
        })
        .then(function (comments) {
            this.comments = comments;
        }.bind(this));
}

While any one of the arrow functions can be replaced by a standard function, there would be very little to gain from doing so. Which version is more readable? I would say the first one.

I think the question whether to use arrow functions or regular functions will become less relevant over time. Most functions will either become class methods, which make away with the function keyword, or they will become classes. Functions will remain in use for patching classes through the Object.prototype. In the mean time I suggest reserving the function keyword for anything that should really be a class method or a class.


Notes

  1. Named arrow functions have been deferred in the ES6 spec. They might still be added a future version.
  2. According to the draft specification "Class declarations/expressions create a constructor function/prototype pair exactly as for function declarations" as long as a class does not use the extend keyword. A minor difference is that class declarations are constants, whereas function declarations are not.
  3. Note on blocks in single statement arrow functions: I like to use a block wherever an arrow function is called for the side effect alone (e.g. assignment). That way it is clear that the return value can be discarded.

这篇关于什么时候应该在ECMAScript 6中使用箭头函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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