箭头函数是一种声明函数的简洁语法,它与普通函数并无本质的区别,差异性更多体现在语法格式上。
//一般写法
function fn (a, b) {
console.log(a, b);
}
//箭头函数形式
const fn = (a, b) => {
console.log(a, b);
}
箭头函数的基本语法有以下特点:;
- 取消了function关键字
- 以赋值符号的形式将函数赋值给函数名
- 参数与函数体之间通过箭头
=>
衔接
就目前来看,箭头函数好像没有比一般函数简单多少,甚至好像更复杂了。
这是因为箭头函数可以根据不同的函数体,参数来省略语法,而一般的函数其形式是固定的。
接下来我带大家一一讲解箭头函数的省略语法:
//一般写法
function (a, b) {
console.log(a, b);
}
//箭头函数形式
(a, b) => {
console.log(a, b);
}
在匿名函数中,一般的函数语法,只能将函数名fn
省略掉,而在箭头函数中,函数名是作为变量的,此时不仅仅可以省略掉函数名fn
,还可以省略掉赋值符号=
以及定义变量的关键字const/var/let
。即整体省略掉:const fn =
到此为止,箭头函数就已经非常简约了,但是箭头函数在一些情况还可以更简单。
由于JavaScript中回调函数较多,我们后续的示例都以匿名函数形式。
当函数中只有一个参数,箭头函数可以省略小括号
这个语法可以省略掉参数的小括号,我们对比一下:
//一般写法
function (a) {
console.log(a);
}
//箭头函数形式
(a) => {
console.log(a);
}
//箭头函数缺省括号形式
a => {
console.log(a);
}
但是要注意,这个缺省参数的括号,只能在只有一个参数的情况下使用,哪怕没有参数也不能缺省括号。
没有参数情况:
//箭头函数没有参数
() => {
console.log(123);
}
当函数体内部只有一条语句,可以省略大括号。
对比:
//一般写法
function (a, b) {
console.log(a, b);
}
//箭头函数形式
(a, b) => {
console.log(a, b);
}
//箭头函数省略大括号形式
(a, b) => console.log(a, b);
当然这种方法仅限于函数内部只有一条语句,此处的语句就是: console.log(a, b)
。但是如果这条语句被写成:
(a, b) => {
console.log(a);
console.log(b);
}
这样的话,由于函数内部有两条语句,大括号就不能省略。
上一个部分我们讲解了当函数内部只有一条语句,可以省略大括号。除此之外:
如果函数只有一条语句,且这个语句是return语句,那么可以同时省略大括号和return。
对比:
//一般写法
function (a, b) {
return a + b;
}
//箭头函数形式
(a, b) => {
return a + b;
}
//箭头函数省略大括号形式
(a, b) => return a + b;//这种写法是错的
//箭头函数省略大括号和return形式
(a, b) => a + b;
不过要注意(a, b) => return a + b
这个写法是错的,在箭头函数省略大括号,且这一条语句是return时,return必须被省略。
至此,我们就将箭头函数的最简洁语法展现给大家了。通过箭头函数的省略语法,在书写一些简单的函数时,可以以非常短的语句完成功能。这就是箭头函数的基本功能。
在函数中,如果我们返回的数据是一个对象,且只有一条返回语句,我们看看这个情况会带来什么误解:
//不省略的箭头函数返回对象
(a, b) => {
return {uname: "张三"};
}
//省略大括号的箭头函数返回对象
(a, b) => return {uname: "张三"};//这种写法是错的
//省略return的箭头函数返回对象
(a, b) => {uname: "张三"};
着重看到这个语句:(a, b) => {uname: "张三"};
请问: {uname: "张三"}
的大括号是函数体的大括号,还是对象的大括号?
我们是程序的编写者,我们当然明确这个大括号属于对象,但是编译器并不能确定,这就会给编译器带来解析的错误。
所以为了避免这个错误,在使用缺省return的箭头函数返回对象时,要额外用一个小括号包起来:
(a, b) => ({uname: "张三"});
其实箭头函数和普通函数的区别也不止语法的缺省。还有一些其它的注意事项。
在一般的函数中,只要谁调用这个函数,那么this就是谁。
在箭头函数中,箭头函数不会创建自己的this,而是从父级继承
给一个案例帮助理解:
const btn = document.querySelector("button");
//一般函数形式
btn.addEventListener("click", function() {
this.style.display = "none";
})
//箭头函数形式
btn.addEventListener("click", () => this.style.display = "none")
在上述代码中,我们用两种函数书写了代码,其功能是:点击按钮btn后,按钮消失。
btn.addEventListener("click", function() {
this.style.display = "none";
})
首先利用了btn
调用函数addEventListener
,然后再执行回调函数。
回调函数是被btn
调用的,所以this
就是btn
, this.style.display = "none"
语句就是把btn
给隐藏,符合要求。
btn.addEventListener("click", () => this.style.display = "none")
这个函数中,回调函数是以箭头函数的形式,虽然回调函数被btn
调用,但是其this
会继承上一级的this
,即全局作用域的window
对象。那么 this.style.display = "none"
就相当于 window.style.display = "none"
,此时不仅不能完成功能,还会报错。
我们看一段构造函数:
function Person(name,age){
this.name = name;
this.age = age;
}
const zhangsan = new Person("张三", 18);
由于构造函数要频繁使用this,而箭头函数没有自己的this,这就会导致其构造函数时出错。
为了方便格式化,箭头函数提供了几种换行方法:
const func = (a, b, c) =>
1;
const func2 = (a, b, c) => (
1
);
const func3 = (a, b, c) => {
return 1;
};
const func4 = (
a,
b,
c,
) => 1;
在function定义的函数中,会存储一个argument对象,用于存储所有的参数(包括超出部分)。但是箭头函数并没有argument。所以箭头函数建议使用剩余参数来进行不定数量的参数传递。
在调用函数时,我们可能不知道用户会传几个参数进来,此时我们有两种方法解决问题,分别是动态参数与剩余参数。
arguments
是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参。
<script>
// 求生函数,计算所有参数的和
function sum() {
console.log(arguments)//[5, 10] [1, 2, 4]
let s = 0
for(let i = 0; i < arguments.length; i++) {
s += arguments[i]
}
console.log(s)
}
// 调用求和函数
sum(5, 10)// 两个参数
sum(1, 2, 4) // 两个参数
script>
在上述代码中,我们调用了两次函数,第一次调用: sum(5, 10)
,那么argument = [5, 10]
第二次调用sum(1, 2, 4)
时,argument = [1, 2, 4]
。
但是这个arguement数组是一个伪数组,并不具备数组的一些方法,我们一般只对其读取内容。
JavaScript中提供了一个符号...
(展开运算符)。当其处于函数参数中时,会将剩余的参数整合为一个数组。
语法:
function fn(a, b, c, ...d){};
在上述语法中,d
就是一个剩余参数。
我列举几个传参情况,帮助大家理解:
调用fn(1,2,3,4,5,6,7,8,9,10)
在fn中只有四个参数,abcd,此时abc按照顺序与参数匹配:
a = 1
b = 2
c = 3
d = 4
多出来的5,6,7,8,9,10
由于剩余参数d的存在,它们被整合为了一个数组:d= [5,6,7,8,9,10]
调用fn(1,2,3)
根据参数一一对应
a = 1
b = 2
c = 3
。
那么d是什么呢?undefined吗?
并不是的,当剩余参数的变量没有匹配到参数时,其为一个空数组。
也就是d = []
此外,剩余参数还有以下注意特点:
- 剩余参数是一个真数组,有数组的方法
- 剩余参数可以在箭头函数中使用
在实际应用中,我们更推荐使用剩余参数代替argument。