[英]When should I use arrow functions in ECMAScript 6?
With () => {}
and function () {}
we are getting two very similar ways to write functions in ES6.使用
() => {}
和function () {}
我们得到了两种非常相似的方法来编写 ES6 中的函数。 In other languages lambda functions often distinguish themselves by being anonymous, but in ECMAScript any function can be anonymous.在其他语言中,lambda 函数通常通过匿名来区分自己,但在 ECMAScript 中,任何 function 都可以是匿名的。 Each of the two types have unique usage domains (namely when
this
needs to either be bound explicitly or explicitly not be bound).这两种类型中的每一种都有独特的使用域(即当
this
需要显式绑定或显式不绑定时)。 Between those domains there are a vast number of cases where either notation will do.在这些领域之间,有大量的情况可以使用任何一种表示法。
Arrow functions in ES6 have at least two limitations: ES6 中的箭头函数至少有两个限制:
new
and cannot be used when creating prototype
new
并且不能在创建prototype
时使用this
bound to scope at initialisationthis
绑定到 scope 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 eg:
是否应该使用箭头函数,例如:
this
variable and we are not creating an object. this
变量不可知,我们也不会创建 object。 I am looking for a guideline to selecting the appropriate function notation in the future version of ECMAScript.我正在寻找在未来版本的 ECMAScript 中选择适当的 function 符号的指南。 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.
指南需要清晰,以便可以将其传授给团队中的开发人员,并且需要保持一致,这样就不需要不断地从一个 function 符号来回重构到另一个符号。
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.这个问题是针对那些在即将到来的 ECMAScript 6 (Harmony) 的上下文中考虑过代码风格并且已经使用过该语言的人。
A while ago our team migrated all its code (a mid-sized AngularJS app) to JavaScript compiled using
Traceur
Babel .不久前,我们的团队将其所有代码(一个中型 AngularJS 应用程序)迁移到使用
Traceur
Babel编译的 JavaScript。 I'm now using the following rule of thumb for functions in ES6 and beyond:我现在对 ES6 及更高版本中的函数使用以下经验法则:
function
in the global scope and for Object.prototype
properties.Object.prototype
属性中使用function
。class
for object constructors.class
用于对象构造函数。=>
everywhere else.=>
。 Why use arrow functions almost everywhere?为什么几乎到处都使用箭头函数?
thisObject
as the root.thisObject
。 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.function
immediately sticks out for defining the scope.function
立即突出来定义作用域。 A developer can always look up the next-higher function
statement to see what the thisObject
is.function
语句来查看thisObject
是什么。 Why always use regular functions on the global scope or module scope?为什么总是在全局作用域或模块作用域上使用常规函数?
thisObject
.thisObject
的函数。window
object (global scope) is best addressed explicitly. window
对象(全局作用域)最好是明确寻址的。Object.prototype
definitions live in the global scope (think String.prototype.truncate
, etc.) and those generally have to be of type function
anyway.Object.prototype
定义都存在于全局范围内(想想String.prototype.truncate
等),而且那些通常必须是function
类型。 Consistently using function
on the global scope helps avoid errors.function
有助于避免错误。function foo(){}
than const foo = () => {}
— in particular outside other function calls.function foo(){}
比const foo = () => {}
更不笨拙——尤其是在其他函数调用之外。 (2) The function name shows in stack traces. 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 identical 2 ECMAScript Harmony draft class definition is almost as compact:然而,功能相同的2 ECMAScript Harmony 草案类定义几乎同样紧凑:
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.在需要对象构造函数的地方,应该考虑将函数转换为
class
如上所示。 The syntax works with anonymous functions/classes as well.该语法也适用于匿名函数/类。
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.自从 ECMAScript 5.1 为我们提供函数式
Array.forEach
、 Array.map
和所有这些函数式编程特性以来,ECMAScript 已经发生了很大变化,这些特性让我们使用了以前会使用for循环的函数。 Asynchronous JavaScript has taken off quite a bit.异步 JavaScript 已经起飞了很多。 ES6 will also ship a
Promise
object, which means even more anonymous functions. ES6 还将提供一个
Promise
对象,这意味着更多的匿名函数。 There is no going back for functional programming.函数式编程没有回头路可走。 In functional JavaScript, arrow functions are preferable over regular functions.
在函数式 JavaScript 中,箭头函数优于常规函数。
Take for instance this (particularly confusing) piece of code 3 :以这段(特别令人困惑的)代码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;
})
}
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.大多数函数要么成为类方法,而无需使用
function
关键字,要么成为类。 Functions will remain in use for patching classes through the Object.prototype
.函数将继续用于通过
Object.prototype
修补类。 In the mean time I suggest reserving the function
keyword for anything that should really be a class method or a class.同时,我建议为任何真正应该是类方法或类的东西保留
function
关键字。
extend
keyword.extend
关键字。 A minor difference is that class declarations are constants, whereas function declarations are not.According to the proposal , arrows aimed "to address and resolve several common pain points of traditional function expressions".根据提案,箭头旨在“解决和解决传统函数表达式的几个常见痛点”。 They intended to improve matters by binding
this
lexically and offering terse syntax.他们打算通过
this
词法上绑定this
并提供简洁的语法来改进问题。
However,然而,
this
lexicallythis
Therefore, arrow functions create opportunities for confusion and errors, and should be excluded from a JavaScript programmer's vocabulary, replaced with function
exclusively.因此,箭头函数创造了混淆和错误的机会,应该从 JavaScript 程序员的词汇表中排除,只用
function
代替。
this
this
this
is problematic: 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);
};
Arrow functions intend to fix the problem where we need to access a property of this
inside a callback.箭头函数旨在解决我们需要在回调中访问
this
属性的问题。 There are already several ways to do that: One could assign this
to a variable, use bind
, or use the third argument available on the Array
aggregate methods.目前已经有几种方法可以做到这一点:人们可以指定
this
一个变量,使用bind
,或使用可用的第三个参数Array
聚集方法。 Yet arrows seem to be the simplest workaround, so the method could be refactored like this:然而箭头似乎是最简单的解决方法,因此该方法可以像这样重构:
this.pages.forEach(page => page.draw(this.settings));
However, consider if the code used a library like jQuery, whose methods bind this
specially.但是,请考虑代码是否使用了像 jQuery 这样的库,其方法专门绑定了
this
。 Now, there are two this
values to deal with:现在,有两个
this
值需要处理:
Book.prototype.render = function () {
var book = this;
this.$pages.each(function (index) {
var $page = $(this);
book.draw(book.currentPage + index, $page);
});
};
We must use function
in order for each
to bind this
dynamically.我们必须使用
function
才能让each
动态绑定this
。 We can't use an arrow function here.我们不能在这里使用箭头函数。
Dealing with multiple this
values can also be confusing, because it's hard to know which this
an author was talking about:具有多个处理
this
值也可能会造成混淆,因为它很难知道哪些this
作者说的是:
function Reader() {
this.book.on('change', function () {
this.reformat();
});
}
Did the author actually intend to call Book.prototype.reformat
?作者是否真的打算调用
Book.prototype.reformat
? Or did he forget to bind this
, and intend to call Reader.prototype.reformat
?还是他忘了绑定
this
,打算调用Reader.prototype.reformat
? If we change the handler to an arrow function, we will similarly wonder if the author wanted the dynamic this
, yet chose an arrow because it fit on one line:如果我们将处理程序更改为箭头函数,我们同样会怀疑作者是否想要动态
this
,但选择了一个箭头,因为它适合一行:
function Reader() {
this.book.on('change', () => this.reformat());
}
One may pose: "Is it exceptional that arrows could sometimes be the wrong function to use? Perhaps if we only rarely need dynamic this
values, then it would still be okay to use arrows most of the time."有人可能会提出:“箭头有时可能是错误的函数使用是不是很特殊?也许如果我们很少需要动态
this
值,那么大多数时间使用箭头仍然可以。”
But ask yourself this: "Would it be 'worth it' to debug code and find that the result of an error was brought upon by an 'edge case?'" I'd prefer to avoid trouble not just most of the time, but 100% of the time.但问问自己:“调试代码并发现错误的结果是由‘边缘情况’引起的,这是否‘值得’?”我宁愿不仅在大多数时候避免麻烦,而且100% 的时间。
There is a better way: Always use function
(so this
can always be dynamically bound), and always reference this
via a variable.有一个更好的方法:始终使用
function
(因此this
始终可以动态绑定),并且始终通过变量引用this
。 Variables are lexical and assume many names.变量是词法的,有很多名字。 Assigning
this
to a variable will make your intentions clear: this
分配给变量将使您的意图明确:
function Reader() {
var reader = this;
reader.book.on('change', function () {
var book = this;
book.reformat();
reader.reformat();
});
}
Furthermore, always assigning this
to a variable (even when there is a single this
or no other functions) ensures one's intentions remain clear even after the code is changed.此外,始终将
this
分配给一个变量(即使只有一个this
或没有其他函数)确保即使在更改代码后仍然保持清晰的意图。
Also, dynamic this
is hardly exceptional.此外,动态
this
几乎不是例外。 jQuery is used on over 50 million websites (as of this writing in February 2016). jQuery 用于超过 5000 万个网站(截至 2016 年 2 月撰写本文时)。 Here are other APIs binding
this
dynamically:以下是动态绑定
this
其他 API:
this
. this
公开其测试方法。this
. this
公开了构建任务的方法。this
. this
方法。EventTarget
with this
.this
的EventTarget
。this
.this
. (Statistics via http://trends.builtwith.com/javascript/jQuery and https://www.npmjs.com.) (通过http://trends.builtwith.com/javascript/jQuery和 https://www.npmjs.com 进行统计。)
You are likely to require dynamic this
bindings already.您可能已经需要动态
this
绑定。
A lexical this
is sometimes expected, but sometimes not;词汇
this
有时是预期的,但有时不是; just as a dynamic this
is sometimes expected, but sometimes not.就像动态一样,
this
有时是预期的,但有时不是。 Thankfully, there is a better way, which always produces and communicates the expected binding.值得庆幸的是,有一种更好的方法,它总是产生和传达预期的绑定。
Arrow functions succeeded in providing a "shorter syntactical form" for functions.箭头函数成功地为函数提供了“更短的语法形式”。 But will these shorter functions make you more successful?
但是这些较短的函数会让你更成功吗?
Is x => x * x
"easier to read" than function (x) { return x * x; }
x => x * x
比function (x) { return x * x; }
更容易阅读吗function (x) { return x * x; }
function (x) { return x * x; }
? function (x) { return x * x; }
? Maybe it is, because it's more likely to produce a single, short line of code.可能是这样,因为它更有可能产生一行简短的代码。 According to Dyson's The influence of reading speed and line length on the effectiveness of reading from screen ,
根据戴森的《阅读速度和行长对屏幕阅读效率的影响》 ,
A medium line length (55 characters per line) appears to support effective reading at normal and fast speeds.
中等行长(每行 55 个字符)似乎支持以正常和快速速度进行有效阅读。 This produced the highest level of comprehension .
这产生了最高层次的修真。 .
. .
.
Similar justifications are made for the conditional (ternary) operator, and for single-line if
statements.条件(三元)运算符和单行
if
语句也有类似的理由。
However, are you really writing the simple mathematical functions advertised in the proposal ?但是,您真的在编写提案中宣传的简单数学函数吗? My domains are not mathematical, so my subroutines are rarely so elegant.
我的领域不是数学的,所以我的子程序很少如此优雅。 Rather, I commonly see arrow functions break a column limit, and wrap to another line due to the editor or style guide, which nullifies "readability" by Dyson's definition.
相反,我经常看到箭头函数打破了列限制,并由于编辑器或样式指南而换行到另一行,这使戴森定义的“可读性”无效。
One might pose, "How about just using the short version for short functions, when possible?".有人可能会提出,“如果可能,只使用简短版本的简短功能怎么样?”。 But now a stylistic rule contradicts a language constraint: "Try to use the shortest function notation possible, keeping in mind that sometimes only the longest notation will bind
this
as expected."但是现在一个文体规则与语言约束相矛盾:“尽量使用最短的函数符号,记住有时只有最长的符号才能按预期绑定
this
。” Such conflation makes arrows particularly prone to misuse.这种混淆使得箭头特别容易被误用。
There are numerous issues with arrow function syntax:箭头函数语法有很多问题:
const a = x =>
doSomething(x);
const b = x =>
doSomething(x);
doSomethingElse(x);
Both of these functions are syntactically valid.这两个函数在语法上都是有效的。 But
doSomethingElse(x);
但是
doSomethingElse(x);
is not in the body of b
.不在
b
的主体中。 It is just a poorly-indented, top-level statement.它只是一个缩进很差的顶级语句。
When expanding to the block form, there is no longer an implicit return
, which one could forget to restore.当扩展到块形式时,不再有隐式
return
,人们可能会忘记恢复。 But the expression may only have been intended to produce a side-effect, so who knows if an explicit return
will be necessary going forward?但是该表达式可能只是为了产生副作用,所以谁知道未来是否需要显式
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);
};
What may be intended as a rest parameter can be parsed as the spread operator:可以将用作剩余参数的内容解析为扩展运算符:
processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest
Assignment can be confused with default arguments:赋值可能与默认参数混淆:
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
Blocks look like objects:块看起来像对象:
(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object
What does this mean?这是什么意思?
() => {}
Did the author intend to create a no-op, or a function that returns an empty object?作者是打算创建一个空操作,还是一个返回空对象的函数? (With this in mind, should we ever place
{
after =>
? Should we restrict ourselves to the expression syntax only? That would further reduce arrows' frequency.) (考虑到这一点,我们是否应该将
{
放在=>
?我们是否应该仅限于表达式语法?这将进一步降低箭头的频率。)
=>
looks like <=
and >=
: =>
看起来像<=
和>=
:
x => 1 ? 2 : 3
x <= 1 ? 2 : 3
if (x => 1) {}
if (x >= 1) {}
To invoke an arrow function expression immediately, one must place ()
on the outside, yet placing ()
on the inside is valid and could be intentional.要立即调用箭头函数表达式,必须将
()
放在外面,而将()
放在里面是有效的并且可能是有意的。
(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function
Although, if one writes (() => doSomething()());
虽然,如果有人写
(() => doSomething()());
with the intention of writing an immediately-invoked function expression, simply nothing will happen.为了编写一个立即调用的函数表达式,什么都不会发生。
It's hard to argue that arrow functions are "more understandable" with all the above cases in mind.考虑到上述所有情况,很难说箭头函数“更容易理解”。 One could learn all the special rules required to utilize this syntax.
可以学习使用这种语法所需的所有特殊规则。 Is it really worth it?
是不是真的值得吗?
The syntax of function
is unexceptionally generalized. function
的语法非常普遍。 To use function
exclusively means the language itself prevents one from writing confusing code.专门使用
function
意味着语言本身可以防止编写令人困惑的代码。 To write procedures that should be syntactically understood in all cases, I choose function
.为了编写在所有情况下都应该在语法上理解的过程,我选择了
function
。
You request a guideline that needs to be "clear" and "consistent."您要求一个需要“清晰”和“一致”的指南。 Using arrow functions will eventually result in syntactically-valid, logically-invalid code, with both function forms intertwined, meaningfully and arbitrarily.
使用箭头函数最终将导致语法有效、逻辑无效的代码,两种函数形式交织在一起,有意义且任意。 Therefore, I offer the following:
因此,我提供以下内容:
function
.function
过程。this
to a variable.this
一个变量。 Do not use () => {}
.() => {}
。Arrow functions were created to simplify function scope
and solving the this
keyword by making it simpler.创建箭头函数是为了简化函数
scope
并通过使其更简单来解决this
关键字。 They utilize the =>
syntax, which looks like an arrow.他们使用
=>
语法,看起来像一个箭头。
Note: It does not replace the existing functions.注意:它不会取代现有功能。 If you replace every function syntax with arrow functions, it's not going to work in all cases.
如果你用箭头函数替换每个函数语法,它不会在所有情况下都有效。
Let's have a look at the existing ES5 syntax.让我们看看现有的 ES5 语法。 If the
this
keyword were inside an object's method (a function that belongs to an object), what would it refer to?如果
this
关键字在对象的方法(属于对象的函数)中,它指的是什么?
var Actor = {
name: 'RajiniKanth',
getName: function() {
console.log(this.name);
}
};
Actor.getName();
The above snippet would refer to an object
and print out the name "RajiniKanth"
.上面的代码片段将引用一个
object
并打印出名称"RajiniKanth"
。 Let's explore the below snippet and see what would this point out here.让我们探索下面的代码片段,看看这会指出什么。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
Now what about if the this
keyword were inside of method's function
?现在如果
this
关键字在method's function
内部呢?
Here this would refer to window object
than the inner function
as its fallen out of scope
.这里 this 指的是
window object
不是inner function
因为它超出了scope
。 Because this
, always references the owner of the function it is in, for this case — since it is now out of scope — the window/global object.因为
this
总是引用它所在函数的所有者,在这种情况下——因为它现在超出了范围——窗口/全局对象。
When it is inside of an object
's method — the function
's owner is the object.当它在
object
的方法内部时—— function
的所有者就是对象。 Thus the this keyword is bound to the object.因此this关键字绑定到对象。 Yet, when it is inside of a function, either stand alone or within another method, it will always refer to the
window/global
object.然而,当它在一个函数内部时,无论是独立的还是在另一个方法中,它总是指向
window/global
对象。
var fn = function(){
alert(this);
}
fn(); // [object Window]
There are ways to solve this problem in our ES5 itself.我们的 ES5 本身有办法解决这个问题。 Let us look into that before diving into ES6 arrow functions on how solve it.
在深入研究 ES6 箭头函数之前,让我们先研究一下如何解决它。
Typically you would, create a variable outside of the method's inner function.通常,您会在方法的内部函数之外创建一个变量。 Now the
'forEach'
method gains access to this
and thus the object's
properties and their values.现在,
'forEach'
方法可以访问this
,从而访问object's
属性及其值。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
var _this = this;
this.movies.forEach(function(movie) {
alert(_this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
Using bind
to attach the this
keyword that refers to the method to the method's inner function
.使用
bind
将引用方法的this
关键字附加到method's inner function
。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(this.name + " has acted in " + movie);
}.bind(this));
}
};
Actor.showMovies();
Now with the ES6 arrow function, we can deal with lexical scoping issue in a simpler way.现在有了 ES6 箭头函数,我们可以用更简单的方式处理词法范围问题。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach((movie) => {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
Arrow functions are more like function statements, except that they bind the this to the parent scope .箭头函数更像是函数语句,只不过它们将this绑定到父作用域。 If the arrow function is in the top scope , the
this
argument will refer to the window/global scope , while an arrow function inside a regular function will have its this argument the same as its outer function.如果箭头函数在顶部作用域中,则
this
参数将引用窗口/全局作用域,而常规函数内的箭头函数的 this 参数将与其外部函数相同。
With arrow functions this
is bound to the enclosing scope at creation time and cannot be changed.使用箭头函数,
this
在创建时绑定到封闭范围并且不能更改。 The new operator, bind, call, and apply have no effect on this. new 运算符、bind、call 和 apply 对此没有影响。
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
// With a traditional function if we don't control
// the context then can we lose control of `this`.
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`
asyncFunction(o, function (param) {
// We made a mistake of thinking `this` is
// the instance of `o`.
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? false
In the above example, we lost the control of this.在上面的例子中,我们失去了对 this 的控制。 We can solve the above example by using a variable reference of
this
or using bind
.我们可以通过使用
this
的变量引用或使用bind
来解决上面的例子。 With ES6, it becomes easier in managing the this
as its bound to lexical scoping .使用 ES6,管理
this
作为其绑定到词法范围变得更容易。
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`.
//
// Because this arrow function is created within
// the scope of `doSomething` it is bound to this
// lexical scope.
asyncFunction(o, (param) => {
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? true
Inside an object literal.在对象字面量内。
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
getName: () => {
alert(this.name);
}
};
Actor.getName();
Actor.getName
is defined with an arrow function, but on invocation it alerts undefined because this.name
is undefined
as the context remains to window
. Actor.getName
是用箭头函数定义的,但在调用时它会警告 undefined 因为this.name
undefined
因为上下文仍然是window
。
It happens because the arrow function binds the context lexically with the window object
... ie, the outer scope.发生这种情况是因为箭头函数在词法上将上下文与
window object
绑定在一起……即外部作用域。 Executing this.name
is equivalent to window.name
, which is undefined.执行
this.name
等价于window.name
,它是未定义的。
The same rule applies when defining methods on a prototype object
.在
prototype object
上定义方法时,同样的规则适用。 Instead of using an arrow function for defining sayCatName method, which brings an incorrect context window
:而不是使用箭头函数来定义 sayCatName 方法,这会带来不正确的
context window
:
function Actor(name) {
this.name = name;
}
Actor.prototype.getName = () => {
console.log(this === window); // => true
return this.name;
};
var act = new Actor('RajiniKanth');
act.getName(); // => undefined
this
in a construction invocation is the newly created object. this
在构造调用中是新创建的对象。 When executing new Fn(), the context of the constructor Fn
is a new object: this instanceof Fn === true
.执行 new Fn() 时,
constructor Fn
的上下文是一个新对象: this instanceof Fn === true
。
this
is setup from the enclosing context, ie, the outer scope which makes it not assigned to newly created object. this
是从封闭上下文中设置的,即外部作用域使其不被分配给新创建的对象。
var Message = (text) => {
this.text = text;
};
// Throws "TypeError: Message is not a constructor"
var helloMessage = new Message('Hello World!');
Arrow function binds the context
statically on declaration and is not possible to make it dynamic.箭头函数在声明时静态绑定
context
,不可能使其动态化。 Attaching event listeners to DOM elements is a common task in client side programming.将事件侦听器附加到 DOM 元素是客户端编程中的一项常见任务。 An event triggers the handler function with this as the target element.
一个事件以 this 作为目标元素触发处理函数。
var button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
this
is window in an arrow function that is defined in the global context. this
是在全局上下文中定义的箭头函数中的窗口。 When a click event happens, the browser tries to invoke the handler function with button context, but arrow function does not change its pre-defined context.当点击事件发生时,浏览器会尝试调用带有按钮上下文的处理函数,但箭头函数不会改变其预定义的上下文。
this.innerHTML
is equivalent to window.innerHTML
and has no sense. this.innerHTML
相当于window.innerHTML
没有意义。
You have to apply a function expression, which allows to change this depending on the target element:您必须应用一个函数表达式,它允许根据目标元素进行更改:
var button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this === button); // => true
this.innerHTML = 'Clicked button';
});
When user clicks the button, this
in the handler function is the button.当用户单击按钮时,处理函数中的
this
就是按钮。 Thus this.innerHTML = 'Clicked button'
correctly modifies the button text to reflect the clicked status.因此
this.innerHTML = 'Clicked button'
正确修改按钮文本以反映点击状态。
Arrow functions - most widely used ES6 feature so far ...
箭头函数 - 迄今为止使用最广泛的 ES6 特性......
Usage: All ES5 functions should be replaced with ES6 arrow functions except in following scenarios:用法:除以下场景外,所有 ES5 函数都应替换为 ES6 箭头函数:
Arrow functions should not be used:箭功能不应使用:
this
/ arguments
in a functionthis
/ arguments
时
this
/ arguments
of their own, they depend upon their outer context.this
/ arguments
,它们依赖于它们的外部上下文。constructor
constructor
this
.this
。this
(which should be object itself).this
(它应该是对象本身)。 Let us understand some of the variants of arrow functions to understand better:让我们了解一些箭头函数的变体以更好地理解:
Variant 1 : When we want to pass more than one argument to a function and return some value from it.变体 1 :当我们想要将多个参数传递给函数并从中返回一些值时。
ES5 version : ES5 版本:
var multiply = function (a, b) {
return a*b;
};
console.log(multiply(5, 6)); // 30
ES6 version : ES6 版本:
var multiplyArrow = (a, b) => a*b;
console.log(multiplyArrow(5, 6)); // 30
Note:笔记:
The function
keyword is not required.该
function
不是必需的关键字。 =>
is required. =>
是必需的。 {}
are optional, when we do not provide {}
return
is implicitly added by JavaScript and when we do provide {}
we need to add return
if we need it. {}
是可选的,当我们不提供{}
return
是由 JavaScript 隐式添加的,当我们提供{}
我们需要在需要时添加return
。
Variant 2 : When we want to pass only one argument to a function and return some value from it.变体2:当我们想通过只使用一个参数的函数,并从它返回一定的价值。
ES5 version : ES5 版本:
var double = function(a) {
return a*2;
};
console.log(double(2)); // 4
ES6 version : ES6 版本:
var doubleArrow = a => a*2;
console.log(doubleArrow(2)); // 4
Note:笔记:
When passing only one argument we can omit the parentheses, ()
.当只传递一个参数时,我们可以省略括号
()
。
Variant 3 : When we do not want to pass any argument to a function and do not want to return any value.变体3:当我们不想传递任何参数的函数,不想返回任何值。
ES5 version : ES5 版本:
var sayHello = function() {
console.log("Hello");
};
sayHello(); // Hello
ES6 version : ES6 版本:
var sayHelloArrow = () => {console.log("sayHelloArrow");}
sayHelloArrow(); // sayHelloArrow
Variant 4 : When we want to explicitly return from arrow functions.变体 4 :当我们想要明确地从箭头函数返回时。
ES6 version : ES6 版本:
var increment = x => {
return x + 1;
};
console.log(increment(1)); // 2
Variant 5 : When we want to return an object from arrow functions.变体 5 :当我们想从箭头函数返回一个对象时。
ES6 version : ES6 版本:
var returnObject = () => ({a:5});
console.log(returnObject());
Note:笔记:
We need to wrap the object in parentheses, ()
.我们需要将对象括在括号
()
。 Otherwise, JavaScript cannot differentiate between a block and an object.否则,JavaScript 无法区分块和对象。
Variant 6 : Arrow functions do not have arguments
(an array like object) of their own.变体 6 :箭头函数没有自己的
arguments
(类似于对象的数组)。 They depend upon outer context for arguments
.它们依赖于
arguments
外部上下文。
ES6 version : ES6 版本:
function foo() {
var abc = i => arguments[0];
console.log(abc(1));
};
foo(2); // 2
Note:笔记:
foo
is an ES5 function, with an arguments
array like object and an argument passed to it is 2
so arguments[0]
for foo
is 2. foo
是一个 ES5 函数,有一个像 object 一样的arguments
数组,传递给它的参数是2
所以foo
arguments[0]
是 2。
abc
is an ES6 arrow function since it does not have its own arguments
. abc
是一个ES6箭头功能,因为它没有自己的arguments
。 Hence it prints arguments[0]
of foo
its outer context instead.因此,它会打印
foo
arguments[0]
其外部上下文。
Variant 7 : Arrow functions do not have this
of their own they depend upon outer context for this
变体7:箭头的功能没有
this
属于自己的,他们依靠的外部背景下this
ES5 version : ES5 版本:
var obj5 = {
greet: "Hi, Welcome ",
greetUser : function(user) {
setTimeout(function(){
console.log(this.greet + ": " + user); // "this" here is undefined.
});
}
};
obj5.greetUser("Katty"); //undefined: Katty
Note:笔记:
The callback passed to setTimeout is an ES5 function and it has its own this
which is undefined in a use-strict
environment.传递给 setTimeout 的回调是一个 ES5 函数,它有自己的
this
在use-strict
环境中未定义。 Hence we get the output:因此我们得到输出:
undefined: Katty
ES6 version : ES6 版本:
var obj6 = {
greet: "Hi, Welcome ",
greetUser : function(user) {
setTimeout(() => console.log(this.greet + ": " + user));
// This here refers to outer context
}
};
obj6.greetUser("Katty"); // Hi, Welcome: Katty
Note:笔记:
The callback passed to setTimeout
is an ES6 arrow function and it does not have its own this
, so it takes it from its outer context that is greetUser
which has this
.传递给回调
setTimeout
是一个ES6箭头功能,它没有自己的this
,所以它需要从它的外部环境正在greetUser
它有this
。 That is obj6
and hence we get the output:那是
obj6
,因此我们得到输出:
Hi, Welcome: Katty
Miscellaneous:各种各样的:
new
with arrow functions.new
与箭头函数一起使用。prototype
property.prototype
属性。this
when an arrow function is invoked through apply
or call
.apply
或call
调用箭头函数时,我们没有绑定this
。I still stand by everything I wrote in my first answer in this thread.我仍然支持我在这个线程的第一个答案中写的所有内容。 However, my opinion on code style has developed since then, so I have a new answer to this question that builds on my last one.
然而,我对代码风格的看法从那时起就发展了,所以我对这个问题有了一个新的答案,这个答案建立在我上一个的基础上。
Regarding lexical this
关于词法
this
In my last answer, I deliberately eschewed an underlying belief I hold about this language, as it was not directly related to the argument I was making.在我的最后一个回答中,我故意回避了我对这种语言持有的潜在信念,因为它与我提出的论点没有直接关系。 Nonetheless, without this being explicitly stated, I can understand why many people simply balk at my recommendation to not use arrows, when they find arrows so useful.
尽管如此,如果没有明确说明这一点,我可以理解为什么许多人在发现箭头如此有用时,只是拒绝我不使用箭头的建议。
My belief is this: we shouldn't be using this
in the first place.我的信念是:我们不应该首先使用
this
。 Therefore, if a person deliberately avoids using this
in his code, then the “lexical this
” feature of arrows is of little to no value.因此,如果一个人故意避免在他的代码中使用
this
,那么箭头的“词法this
”特性就几乎没有价值。 Also, under the premise that this
is a bad thing, arrow's treatment of this
is less of a “good thing;”此外,前提下,
this
是一件坏事,箭头的治疗this
是更小的“好事”; instead, it's more of a form of damage control for another bad language feature.相反,它更像是另一种糟糕的语言功能的损害控制形式。
I figure that this either does not occur to some people, but even to those to whom it does, they must invariably find themselves working within codebases where this
appears a hundred times per file, and a little (or a lot) of damage control is all a reasonable person could hope for.我想,这要么不发生的一些人,但即使是那些谁这样做,他们必须总是发现自己的代码库,其中内工作
this
似乎每个文件一百倍,并损害控制的一点点(或很多)是一个理性的人所能期望的一切。 So arrows can be good, in a way, when they make a bad situation better.因此,在某种程度上,当箭头使糟糕的情况变得更好时,它们可能是好的。
Even if it is easier to write code with this
with arrows than without them, the rules for using arrows remain very complex (see: current thread).即使是更容易编写代码与
this
用箭头比没有他们,使用箭头规则仍然很复杂(参见:当前线程)。 Thus, guidelines are neither “clear” nor “consistent,” as you've requested.因此,正如您所要求的那样,指南既不“清晰”也不“一致”。 Even if programmers know about arrows' ambiguities, I think they shrug and accept them anyway, because the value of lexical
this
overshadows them.即使程序员知道箭含糊不清,我认为他们耸耸肩,反正接受他们,因为词汇值
this
黯然失色他们。
All this is a preface to the following realization: if one does not use this
, then the ambiguity about this
that arrows normally cause becomes irrelevant.所有这些都是以下认识的序言:如果不使用
this
,那么箭头通常引起的关于this
的歧义就变得无关紧要了。 Arrows become more neutral in this context.在这种情况下,箭头变得更加中性。
Regarding terse syntax关于简洁的语法
When I wrote my first answer, I was of the opinion that even slavish adherence to best practices was a worthwhile price to pay if it meant I could produce more perfect code.当我写下我的第一个答案时,我认为即使是对最佳实践的盲目遵守也是值得付出的代价,如果这意味着我可以生成更完美的代码。 But I eventually came to realize that terseness can serve as a form of abstraction that can improve code quality, too — enough so to justify straying from best practices sometimes.
但我最终意识到,简洁也可以作为一种抽象形式,可以提高代码质量——足以证明有时偏离最佳实践是合理的。
In other words: dammit, I want one-liner functions, too!换句话说:该死的,我也想要单行函数!
Regarding a guideline关于指南
With the possibility of this
-neutral arrow functions, and terseness being worth pursuit, I offer the following more lenient guideline:由于
this
中性箭头函数的可能性,以及值得追求的简洁性,我提供以下更宽松的指导方针:
this
.this
。In addition to the great answers so far, I'd like to present a very different reason why arrow functions are in a certain sense fundamentally better than "ordinary" JavaScript functions.除了到目前为止的出色答案之外,我想提出一个非常不同的原因,为什么箭头函数在某种意义上从根本上优于“普通”JavaScript 函数。
For the sake of discussion, let's temporarily assume we use a type checker like TypeScript or Facebook's "Flow".为了便于讨论,让我们暂时假设我们使用类型检查器,如TypeScript或 Facebook 的“Flow”。 Consider the following toy module, which is valid ECMAScript 6 code plus Flow type annotations (I'll include the untyped code, which would realistically result from Babel, at the end of this answer, so it can actually be run):
考虑以下玩具模块,它是有效的 ECMAScript 6 代码加上 Flow 类型注释(我将在本答案的末尾包含实际上由 Babel 产生的无类型代码,因此它实际上可以运行):
export class C { n : number; f1: number => number; f2: number => number; constructor(){ this.n = 42; this.f1 = (x:number) => x + this.n; this.f2 = function (x:number) { return x + this.n;}; } }
Now see what happens when we use the class C from a different module, like this:现在看看当我们使用来自不同模块的类 C 时会发生什么,如下所示:
let o = { f1: new C().f1, f2: new C().f2, n: "foo" }; let n1: number = o.f1(1); // n1 = 43 console.log(n1 === 43); // true let n2: number = o.f2(1); // n2 = "1foo" console.log(n2 === "1foo"); // true, not a string!
As you can see, the type checker failed here: f2 was supposed to return a number, but it returned a string!如您所见,类型检查器在这里失败了:f2 应该返回一个数字,但它返回了一个字符串!
Worse, it seems that no conceivable type checker can handle ordinary (non-arrow) JavaScript functions, because the "this" of f2 does not occur in the argument list of f2, so the required type for "this" could not possibly be added as an annotation to f2.更糟糕的是,似乎没有任何可以想象的类型检查器可以处理普通的(非箭头)JavaScript 函数,因为 f2 的“this”没有出现在 f2 的参数列表中,因此不可能添加“this”所需的类型作为 f2 的注释。
Does this problem also affect people who don't use type checkers?这个问题是否也会影响不使用类型检查器的人? I think so, because even when we have no static types, we think as if they're there.
我认为是这样,因为即使我们没有静态类型,我们也会认为它们就在那里。 ("The first parameters must be a number, the second one a string" etc.) A hidden "this"-argument which may or may not be used in the function's body makes our mental bookkeeping harder.
(“第一个参数必须是一个数字,第二个参数必须是一个字符串”等等)一个隐藏的“this”参数可能会或可能不会在函数体中使用,这让我们的心理簿记更加困难。
Here is the runnable untyped version, which would be produced by Babel:这是可运行的无类型版本,它将由 Babel 生成:
class C { constructor() { this.n = 42; this.f1 = x => x + this.n; this.f2 = function (x) { return x + this.n; }; } } let o = { f1: new C().f1, f2: new C().f2, n: "foo" }; let n1 = o.f1(1); // n1 = 43 console.log(n1 === 43); // true let n2 = o.f2(1); // n2 = "1foo" console.log(n2 === "1foo"); // true, not a string!
我更喜欢在不需要访问本地this
任何时候使用箭头函数,因为箭头函数不绑定自己的this 、参数、 super 或 new.target 。
Arrow functions or lambdas , were introduced in ES 6. Apart from its elegance in minimal syntax, the most notable functional difference is scoping of this
inside an arrow function箭头函数或lambdas是在 ES 6 中引入的。 除了它在最小语法中的优雅之外,最显着的功能差异是箭头函数内部的
this
作用域
In regular function expressions, the
this
keyword is bound to different values based on the context in which it is called.在正则函数表达式中,
this
关键字根据调用它的上下文绑定到不同的值。In arrow functions ,
this
is lexically bound, which means it closes overthis
from the scope in which the arrow function was defined (parent-scope), and does not change no matter where and how it is invoked / called.在箭头函数中,
this
是词法绑定的,这意味着它从定义箭头函数的范围(父范围)关闭this
,并且无论在何处以及如何调用/调用它都不会改变。
// this = global Window
let objA = {
id: 10,
name: "Simar",
print () { // same as print: function()
console.log(`[${this.id} -> ${this.name}]`);
}
}
objA.print(); // logs: [10 -> Simar]
objA = {
id: 10,
name: "Simar",
print: () => {
// Closes over this lexically (global Window)
console.log(`[${this.id} -> ${this.name}]`);
}
};
objA.print(); // logs: [undefined -> undefined]
In the case of objA.print()
when print()
method defined using regular function
, it worked by resolving this
properly to objA
for method invocation, but failed when defined as an arrow =>
function.在
objA.print()
的情况下,当使用常规function
定义print()
方法时,它通过将this
正确解析为objA
进行方法调用来工作,但在定义为箭头=>
函数时失败。 It is because this
in a regular function when invoked as a method on an object ( objA
), is the object itself.这是因为
this
在常规函数中作为对象 ( objA
) 上的方法调用时,是对象本身。
However, in case of an arrow function, this
gets lexically bound to the the this
of the enclosing scope where it was defined (global / Window in our case) and stays it stays same during its invocation as a method on objA
.然而,在箭头函数的情况下,
this
在词法上绑定到它被定义的封闭范围的this
(在我们的例子中是全局/窗口),并在它作为objA
上的方法调用期间保持不变。
There are advantages of an arrow-functions over regular functions in method(s) of an object, but only when this
is expected to be fixed and bound at the time of definition.有超过常规功能的箭头功能优点在方法的对象的(一个或多个),但仅当
this
预期是固定的,并在定义时的约束。
/* this = global | Window (enclosing scope) */
let objB = {
id: 20,
name: "Paul",
print () { // Same as print: function()
setTimeout( function() {
// Invoked async, not bound to objB
console.log(`[${this.id} -> ${this.name}]`);
}, 1)
}
};
objB.print(); // Logs: [undefined -> undefined]'
objB = {
id: 20,
name: "Paul",
print () { // Same as print: function()
setTimeout( () => {
// Closes over bind to this from objB.print()
console.log(`[${this.id} -> ${this.name}]`);
}, 1)
}
};
objB.print(); // Logs: [20 -> Paul]
In the case of objB.print()
where the print()
method is defined as function that invokes console.log(
[${this.id} -> {this.name}] )
asynchronously as a call-back on setTimeout
, this
resolved correctly to objB
when an arrow function was used as call-back, but failed when the call-back was defined as as regular function.在
objB.print()
的情况下, print()
方法被定义为调用console.log(
[${this.id} -> {this.name}] )
函数作为setTimeout
上的回调,当箭头函数用作objB
时, this
正确解析为objB
但当回调定义为常规函数时失败。
It is because the arrow =>
function, passed to setTimeout(()=>..)
, closed over this
lexically from its parent, ie, invocation of objB.print()
which defined it.这是因为传递给
setTimeout(()=>..)
的箭头=>
函数在词法上从其父级关闭了this
,即调用定义它的objB.print()
。 In other words, the arrow =>
function passed in to to setTimeout(()==>...
bound to objB
as its this
because the invocation of objB.print()
this
was objB
itself.换句话说,箭头
=>
函数传入到setTimeout(()==>...
绑定到objB
作为它的this
因为objB.print()
this
的调用是objB
本身。
We could easily use Function.prototype.bind()
to make the call-back defined as a regular function work, by binding it to the correct this
.我们可以很容易地使用
Function.prototype.bind()
使定义为常规函数的回调工作,通过将其绑定到正确的this
。
const objB = {
id: 20,
name: "Singh",
print () { // The same as print: function()
setTimeout( (function() {
console.log(`[${this.id} -> ${this.name}]`);
}).bind(this), 1)
}
}
objB.print() // logs: [20 -> Singh]
However, arrow functions come in handy and are less error prone for the case of async call-backs where we know the this
at the time of the functions definition to which it gets and should be bound.然而,箭头函数派上用场,并且在异步回调的情况下不太容易出错,在这种情况下,我们知道
this
在它获取并应该绑定到的函数定义时。
this
needs to change across invocationsthis
需要跨调用更改Anytime, we need a function whose this
can be changed at the time of invocation, we can't use arrow functions.任何时候,我们都需要一个可以在调用时更改
this
的函数,我们不能使用箭头函数。
/* this = global | Window (enclosing scope) */
function print() {
console.log(`[${this.id} -> {this.name}]`);
}
const obj1 = {
id: 10,
name: "Simar",
print // The same as print: print
};
obj.print(); // Logs: [10 -> Simar]
const obj2 = {
id: 20,
name: "Paul",
};
printObj2 = obj2.bind(obj2);
printObj2(); // Logs: [20 -> Paul]
print.call(obj2); // logs: [20 -> Paul]
None of the above will work with arrow function const print = () => { console.log(
[${this.id} -> {this.name}] );}
as this
can't be changed and will stay bound to the this
of the enclosing scope where it was defined (global / Window).以上都不适用于箭头函数
const print = () => { console.log(
[${this.id} -> {this.name}] );}
因为this
无法更改并且将保持绑定到定义它的封闭范围的this
(全局/窗口)。
In all these examples, we invoked the same function with different objects ( obj1
and obj2
) one after the another, both of which were created after the print()
function was declared.在所有这些示例中,我们使用不同的对象(
obj1
和obj2
)一个接一个地调用相同的函数,这两个对象都是在声明print()
函数之后创建的。
These were contrived examples, but let's think about some more real life examples.这些都是人为的例子,但让我们考虑一些更真实的例子。 If we had to write our
reduce()
method similar to one that works on arrays
, we again can't define it as a lambda, because it needs to infer this
from the invocation context, ie, the array on which it was invoked.如果我们必须编写类似于处理
arrays
reduce()
方法,我们又不能将其定义为 lambda,因为它需要从调用上下文(即调用它的数组)中推断出this
。
For this reason, constructor functions can never be defined as arrow functions, as this
for a constructor function can not be set at the time of its declaration.出于这个原因,构造函数永远不能定义为箭头函数,因为不能在声明时设置构造函数的
this
。 Every time a constructor function is invoked with the new
keyword, a new object is created which then gets bound to that particular invocation.每次使用
new
关键字调用构造函数时,都会创建一个新对象,然后将其绑定到该特定调用。
Also when when frameworks or systems accept a callback function(s) to be invoked later with dynamic context this
, we can't use arrow functions as again this
may need to change with every invocation.此外,当框架或系统接受稍后使用动态上下文
this
调用的回调函数时,我们不能再次使用箭头函数,因为this
可能需要随每次调用而更改。 This situation commonly arises with DOM event handlers.这种情况通常出现在 DOM 事件处理程序中。
'use strict'
var button = document.getElementById('button');
button.addEventListener('click', function {
// web-api invokes with this bound to current-target in DOM
this.classList.toggle('on');
});
var button = document.getElementById('button');
button.addEventListener('click', () => {
// TypeError; 'use strict' -> no global this
this.classList.toggle('on');
});
This is also the reason why in frameworks like Angular 2+ and Vue.js expect the template-component binding methods to be regular function / methods as this
for their invocation is managed by the frameworks for the binding functions.这也是为什么像角2+和Vue.js框架期望为模板组件绑定的方法是定时功能/方法的原因
this
为他们的调用由为绑定功能的框架进行管理。 (Angular uses Zone.js to manage an async context for invocations of view-template binding functions.) (Angular 使用 Zone.js 来管理视图模板绑定函数调用的异步上下文。)
On the other hand, in React , when we want pass a component's method as an event-handler, for example, <input onChange={this.handleOnchange} />
, we should define handleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}
as an arrow function as for every invocation.另一方面,在React 中,当我们想要将组件的方法作为事件处理程序传递时,例如
<input onChange={this.handleOnchange} />
,我们应该定义handleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}
作为每次调用的箭头函数。 We want this to be the same instance of the component that produced the JSX for the rendered DOM element.我们希望它与为渲染的 DOM 元素生成 JSX 的组件实例相同。
This article is also available in my Medium publication.这篇文章也可以在我的 Medium出版物中找到。 If you like the article, or have any comments and suggestions, please clap or leave comments on Medium .
如果你喜欢这篇文章,或者有什么意见和建议,请在Medium上鼓掌或留言。
In a simple way,简单来说,
var a = 20; function a() {this.a = 10; console.log(a);}
//20, since the context here is window.
Another instance:另一个例子:
var a = 20;
function ex(){
this.a = 10;
function inner(){
console.log(this.a); // Can you guess the output of this line?
}
inner();
}
var test = new ex();
Ans: The console would print 20.答:控制台会打印 20。
The reason being whenever a function is executed its own stack is created, in this example the ex
function is executed with the new
operator so a context will be created, and when inner
is executed it JavaScript would create a new stack and execute the inner
function in a global context
though there is a local context.原因是每当一个函数被执行时,它自己的堆栈就会被创建,在这个例子中,
ex
函数是用new
操作符执行的,因此将创建一个上下文,当执行inner
时,JavaScript 将创建一个新堆栈并执行inner
函数尽管存在局部上下文,但在global context
中。
So, if we want the inner
function to have a local context, which is ex
, then we need to bind the context to the inner function.因此,如果我们希望
inner
函数具有局部上下文,即ex
,那么我们需要将上下文绑定到内部函数。
Arrows solve this problem.箭头解决了这个问题。 Instead of taking the
Global context
, they take the local context
if any exist.它们不采用
Global context
,而是采用local context
如果存在)。 In the *given example, it will take new ex()
as this
.在*给定的示例中,它将采用
new ex()
作为this
。
So, in all cases where binding is explicit, arrows solve the problem by defaults.因此,在所有绑定是显式的情况下,默认情况下箭头可以解决问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.