根据提案,箭头旨在“解决和解决传统函数表达式的几个常见痛点”。他们打算通过this
词法绑定和提供简洁的语法来改善问题。
然而,
- 不能始终如一地在
this
词汇上绑定
- 箭头函数语法微妙且模棱两可
因此,箭头函数会产生混淆和错误的机会,应该从 JavaScript 程序员的词汇表中排除,替换为function
独占。
关于词汇this
this
有问题:
function Book(settings) {
this.settings = settings;
this.pages = this.createPages();
}
Book.prototype.render = function () {
this.pages.forEach(function (page) {
page.draw(this.settings);
}, this);
};
箭头函数旨在解决我们需要访问this
回调内部属性的问题。已经有几种方法可以做到这一点:一种可以分配this
给变量,使用,或使用聚合方法bind
上可用的第三个参数。Array
然而,箭头似乎是最简单的解决方法,因此可以像这样重构该方法:
this.pages.forEach(page => page.draw(this.settings));
但是,考虑一下代码是否使用了像 jQuery 这样的库,它的方法是this
专门绑定的。现在,有两个this
值需要处理:
Book.prototype.render = function () {
var book = this;
this.$pages.each(function (index) {
var $page = $(this);
book.draw(book.currentPage + index, $page);
});
};
我们必须使用function
为了动态each
绑定this
。我们不能在这里使用箭头函数。
处理多个this
值也可能令人困惑,因为很难知道this
作者在谈论哪个:
function Reader() {
this.book.on('change', function () {
this.reformat();
});
}
作者真的打算打电话Book.prototype.reformat
吗?还是他忘记绑定了this
,打算打电话Reader.prototype.reformat
?如果我们将处理程序更改为箭头函数,我们同样会怀疑作者是否想要动态this
,但选择了一个箭头,因为它适合一行:
function Reader() {
this.book.on('change', () => this.reformat());
}
有人可能会提出:“箭头有时可能是错误的函数,这很奇怪吗?也许如果我们只是很少需要动态this
值,那么大多数时候使用箭头仍然是可以的。”
但是问问自己这个问题:“调试代码并发现错误的结果是由‘极端情况’引起的‘值得’吗?”我宁愿避免麻烦,不仅仅是大多数时候,而是100% 的时间。
有一个更好的方法:始终使用function
(因此this
始终可以动态绑定),并且始终this
通过变量进行引用。变量是词法的并采用许多名称。分配this
给变量将使您的意图明确:
function Reader() {
var reader = this;
reader.book.on('change', function () {
var book = this;
book.reformat();
reader.reformat();
});
}
此外,始终分配this
给一个变量(即使只有一个this
或没有其他函数)确保即使在代码更改后,一个人的意图仍然清晰。
此外,动态this
几乎不例外。jQuery 被用于超过 5000 万个网站(截至 2016 年 2 月撰写本文时)。以下是其他动态绑定的 API this
:
- Mocha(昨天下载量约为 120k)通过
this
.
- Grunt(昨天下载量约为 63k)通过
this
.
- Backbone(昨天下载了约 22k 次)定义了访问
this
.
- 事件 API(如 DOM)指的是
EventTarget
with this
。
- 修补或扩展的原型API 指的是带有
this
.
(通过http://trends.builtwith.com/javascript/jQuery和 https://www.npmjs.com 统计。)
您可能已经需要动态this
绑定。
有时会出现词汇this
,但有时不会;就像this
有时期望的动态一样,但有时却不是。值得庆幸的是,有一种更好的方法,它总是产生和传达预期的绑定。
关于简洁的语法
箭头函数成功地为函数提供了一种“更短的句法形式”。但是这些更短的功能会让你更成功吗?
“x => x * x
更容易阅读”比function (x) { return x * x; }
?也许是这样,因为它更有可能产生一个单一的、短的代码行。根据戴森的《阅读速度和行长对屏幕阅读效果的影响》,
中等长度的行(每行 55 个字符)似乎支持以正常和快速的速度进行有效阅读。这产生了最高层次的悟性。. .
条件(三元)运算符和单行if
语句也有类似的理由。
但是,您真的在编写提案中宣传的简单数学函数吗?我的领域不是数学的,所以我的子程序很少如此优雅。相反,我经常看到箭头函数打破了列限制,并且由于编辑器或样式指南而换行到另一行,这使 Dyson 定义的“可读性”无效。
有人可能会提出,“如果可能的话,只使用简短版本的简短功能怎么样?”。但是现在一个风格规则与语言约束相矛盾:“尽量使用最短的函数符号,记住有时只有最长的符号才能this
按预期绑定。” 这种合并使得箭头特别容易被误用。
箭头函数语法有很多问题:
const a = x =>
doSomething(x);
const b = x =>
doSomething(x);
doSomethingElse(x);
这两个函数在语法上都是有效的。却不doSomethingElse(x);
在体内b
。这只是一个缩进不佳的顶级语句。
当扩展到块形式时,不再有隐含return
的 ,人们可能会忘记恢复它。但是这个表达式可能只是为了产生副作用,所以谁知道未来是否return
需要显式?
const create = () => User.create();
const create = () => {
let user;
User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
const create = () => {
let user;
return User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
可能打算作为休息参数的内容可以解析为扩展运算符:
processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest
赋值可能与默认参数混淆:
const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parentheses
块看起来像对象:
(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object
这是什么意思?
() => {}
作者是打算创建一个无操作,还是一个返回空对象的函数?(考虑到这一点,我们是否应该放置{
在 之后=>
?我们是否应该仅限于表达式语法?这将进一步降低箭头的频率。)
=>
看起来像<=
和>=
:
x => 1 ? 2 : 3
x <= 1 ? 2 : 3
if (x => 1) {}
if (x >= 1) {}
要立即调用箭头函数表达式,必须放在()
外面,但放在()
里面是有效的并且可能是有意的。
(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function
虽然,如果一个人(() => doSomething()());
的意图是编写一个立即调用的函数表达式,那么什么都不会发生。
考虑到上述所有情况,很难说箭头函数“更容易理解”。人们可以学习使用这种语法所需的所有特殊规则。是不是真的值得吗?
的语法function
非常通用。独占意味着语言本身可以function
防止编写令人困惑的代码。为了编写在所有情况下都应该在语法上理解的过程,我选择function
.
关于指导方针
您要求的指南需要“清晰”和“一致”。使用箭头函数最终将导致语法有效、逻辑无效的代码,两种函数形式相互交织,有意义且任意。因此,我提供以下内容:
ES6 中的函数表示法指南:
- 始终使用
function
.
- 始终分配
this
给变量。不要使用() => {}
.