原文:
https://medium.freecodecamp.org/arrow-functions-in-javascript-2f8bf7df5077
箭头函数是搭建现代 Web 应用程序中一种新的基础构件。在本文中,你将会学习箭头函数如何使代码更简洁、使“this”关键字更易于管理;还将学习隐式返回、使用箭头函数记录日志以及隐式返回结合对象一起使用的方法。
如果你喜欢通过视频而不是文本学习,这是视频链接:
https://youtu.be/dB1KA-yz65s
。
与常规函数相比,使用箭头函数有两个优点。首先,箭头函数使代码更简洁。其次,使用箭头函数使得管理“this”关键字更容易。
我见过那些初次学习箭头函数的开发者,对于他们来说箭头函数本身的概念并不是很难理解。你可能已经熟悉函数、函数特性、函数用例等内容,但是当你第一次接触箭头函数语法时还是比较容易困惑的。因此,我们要慢慢来,首先介绍一下与常用函数相比,箭头函数的语法是怎样的。
下面是一个基本函数声明和函数表达式的范例:
1
2
3
4
5
6
7
8
|
// 函数声明
function
add
(
x
,
y
)
{
return
x
+
y
;
}
// 函数表达式
var
add
=
function
(
x
,
y
)
{
return
x
+
y
;
}
|
现在,如果我们想要将函数表达式改为一个箭头函数,我们可以这样做:
1
2
3
4
5
6
7
8
|
//常用函数表达式
var
add
=
function
(
x
,
y
)
{
return
x
+
y
;
}
//箭头函数
var
add
=
(
x
,
y
)
=>
{
return
x
+
y
;
}
|
使用箭头函数最难的是习惯它的语法形式,一旦你适应了并坚持下去,相信你将会深入的理解并掌握它。
现在,你可能想知道使用箭头函数带来的所有好处。其实,上面的例子并没有充分显示出箭头函数的优势,我发现当使用匿名函数时,箭头函数的优势发挥的最为明显。通过查看另一个使用
.map
的基本例子,可以让我们对箭头函数的语法更为熟悉。
1
2
3
4
|
users
.
map
(
function
()
{
})
users
.
map
(()
=>
{
})
|
好了,熟悉的差不多了,接下来让我们进行深入的学习。
假设我们有一个函数:
getTweets
,该函数接收用户 id 作为入参,通过访问一个简单的 API 接口后,返回所有星数和转发次数超过 50 的 Twitter 用户。
使用 promise 构造函数定义,这个函数看起来是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function
getTweets
(
uid
)
{
return
fetch
(
'https://api.users.com/'
+
uid
)
.
then
(
function
(
response
)
{
return
response
.
json
()
})
.
then
(
function
(
response
)
{
return
response
.
data
}).
then
(
function
(
tweets
)
{
return
tweets
.
filter
(
function
(
tweet
)
{
return
tweet
.
stars
>
50
})
}).
then
(
function
(
tweets
)
{
return
tweets
.
filter
(
function
(
tweet
)
{
return
tweet
.
rts
>
50
})
})
}
|
是的,功能虽然实现了,但是这个函数还不是最完美的。尽管具体的实现步骤是紧凑的,但是想法有点过于平常了。根据上述对箭头函数的理解,我们来看一下可以怎样改进
getTweets
函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function
getTweets
(
uid
)
{
return
fetch
(
'https://api.users.com/'
+
uid
)
.
then
((
response
)
=>
{
return
response
.
json
()
})
.
then
((
response
)
=>
{
return
response
.
data
}).
then
((
tweets
)
=>
{
return
tweets
.
filter
((
tweet
)
=>
{
return
tweet
.
stars
>
50
})
}).
then
((
tweets
)
=>
{
return
tweets
.
filter
((
tweet
)
=>
{
return
tweet
.
rts
>
50
})
})
}
|
好的,酷极了。但是除了不需要写
function
之外,和上面的写法几乎是一致的。虽然这种写法是有益的,却没有什么值得炫耀的。还是让我们来看一下使用箭头函数带来的下一个优点:“隐式返回”。
使用箭头函数时,如果你的函数是一个“简单的函数体”(对于单行函数的称呼),那么你可以省略“return”关键字,该值会自动(隐式)返回。
所以,前面的
add
示例修改后如下:
1
2
3
4
5
6
|
//普通函数表达式
var
add
=
function
(
x
,
y
)
{
return
x
+
y
;
}
//使用箭头函数的隐式返回
var
add
=
(
x
,
y
)
=>
x
+
y
;
|
更重要的是,修改后的
getTweets
函数示例如下:
1
2
3
4
5
6
7
|
function
getTweets
(
uid
)
{
return
fetch
(
'https://api.users.com/'
+
uid
)
.
then
((
response
)
=>
response
.
json
())
.
then
((
response
)
=>
response
.
data
)
.
then
((
tweets
)
=>
tweets
.
filter
((
tweet
)
=>
tweet
.
stars
>
50
))
.
then
((
tweets
)
=>
tweets
.
filter
((
tweet
)
=>
tweet
.
rts
>
50
))
}
|
该代码不仅容易编写,更重要的是,它更容易阅读。
如果箭头函数只有一个入参,那么我们可以做的进一步的修改是省略该参数周围的
()
。考虑到这一点,
getTweets
函数可以这样写:
1
2
3
4
5
6
7
|
function
getTweets
(
uid
)
{
return
fetch
(
'https://api.users.com/'
+
uid
)
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
data
)
.
then
(
tweets
=>
tweets
.
filter
(
tweet
=>
tweet
.
stars
>
50
))
.
then
(
tweets
=>
tweets
.
filter
(
tweet
=>
tweet
.
rts
>
50
))
}
|
总的来说,我认为上面做的每一种改变都是巨大的进步。
箭头函数的另一个优点就是如何管理“this”关键字。如果你对“this ”关键字不熟悉,我推荐看一下
WTF is this
。
让我们看下使用 ES5 语法编写的典型 React 代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
Popular
extends
React
.
Component
{
constructor
(
props
)
{
super
();
this
.
state
=
{
repos
:
null
,
};
this
.
updateLanguage
=
this
.
updateLanguage
.
bind
(
this
);
}
componentDidMount
()
{
this
.
updateLanguage
(
'javascript'
)
}
updateLanguage
(
lang
)
{
api
.
fetchPopularRepos
(
lang
)
.
then
(
function
(
repos
)
{
this
.
setState
(
function
()
{
return
{
repos
:
repos
}
});
});
}
render
()
{
// Stuff
}
}
|
当组件加载时,它会向 API ( Github API )发出请求来获取当下 JavaScript 最流行的库。当组件获得库的数据时,它将会接受并更新其本地状态,至少我们希望它能这样做。很遗憾,实际上它并没有这样做。相反,我们会得到一个错误,你能指出上面代码中的 bug 吗?
上面代码将会抛出的错误是“无法读取未定义的 setState ”。讨论为什么出现这个错误已经在本篇文章讨论范围之外了(如果你需要请看
WTF is this
)。另外, ES5 中典型的解决方法是使用了
.bind
来绑定 this ,具体内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
Popular
extends
React
.
Component
{
constructor
(
props
)
{
super
();
this
.
state
=
{
repos
:
null
,
};
this
.
updateLanguage
=
this
.
updateLanguage
.
bind
(
this
);
}
componentDidMount
()
{
this
.
updateLanguage
(
'javascript'
)
}
updateLanguage
(
lang
)
{
|