入门
在 JavaScript ES6 之前,有几种声明函数的方法,可以是函数声明,如下所示:
function add(a, b) {
return a + b;
}
console.log(add(2, 3))
或者用函数表达式:
var add = function(a, b) {
return a + b;
}
console.log(add(2, 3))
箭头函数语法
现在,让我们将上面的两个函数转换为箭头函数,如下所示:
var add = (a, b) => {
return a + b;
}
console.log(add(2, 3));
我们完全摆脱了function
关键字,而是使用了=>
看起来像箭头的语法,所以人们称之为“箭头函数”或“胖箭头函数”(不知道为什么它是胖的)。
让我们分解这个箭头函数的语法。首先,箭头函数需要是函数表达式,不能像普通函数那样单独放置。参数像普通函数一样在括号内传递。接下来,=>
表示这是一个箭头函数,后面是函数体。我们像普通函数一样调用箭头函数。这是一般语法:
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }
// The parameter list for a function with no parameters should be written with a pair of parentheses.
() => { statements }
带参数的箭头函数:
var myFunction = (para1, para2) => {
// do something
}
如果你的函数只有一个表达式,你可以省略大括号和return
关键字,并在一行上写一个完整的函数:
var myFunction = (para1, para2) => para1 + para2;
这样做时,箭头函数允许您有一个隐式 return,这意味着在调用没有 return 关键字的函数时将返回表达式。
var myFunction = (para1, para2) => para1 + para2;
myFunction(2, 3); // 5
var greeting = name => "Hello, my name is " + name;
greeting('Nam'); // Hello, my name is Nam
这些功能等于:
var myFunction = (para1, para2) => { return para1 + para2; }
myFunction(2, 3); // 5
var greeting = name => { return "Hello, my name is " + name; }
greeting('Nam'); // Hello, my name is Nam
如果你在括号内写了一段代码来包含你的函数体,即使它只是一条语句,如果你想返回一些东西,你仍然必须显式地使用 return 关键字。
如果您想隐式返回一个对象,请确保将其包装在括号内以避免混淆:
var test = () => { name: 'Jessica' };
test(); // undefined
// OK
var test = () => ({ name: 'Jessica' })
test(); // { name: 'Jessica' }
当函数只有一个参数时,围绕它的括号是可选的:
var square = num => num * num;
// OK, also
var square = (num) => num * num;
如果函数有两个或两个以上的参数,括号是强制性的,同样的规则适用于没有参数的函数:
var a = (para1, para2) => {
// do something
}
var b = (para1, para2, para3) => {
// do something
}
var c = () => {
// do something
}
箭头函数也支持 ES6 中带有 rest 和 default 参数的一些高级语法:
(param1, param2, ...rest) => { statements }
var multiply = (a, b, ...c) => {
var accumulator = a * b;
for (var i of c) {
accumulator *= i;
}
return accumulator;
};
multiply(1, 2, 3, 4, 5); // 120
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
var x = (para1 = 'JavaScript') => {
return "I want to learn " + para1;
}
x(); // I want to learn JavaScript
x('HTML'); // I want to learn HTML
我们将在接下来的文章中了解更多关于扩展运算符、休息和默认参数的信息。
箭头函数和“THIS”关键字
“this”关键字可能是 JavaScript 中最难以捉摸的部分之一。我已经写了一篇关于箭头函数中“ this ”关键字的综合文章。查看这篇文章以了解有关“ this”关键字的更多信息。
一般来说,对于常规函数,我们总是必须跟踪“this”上下文并记住正确绑定它,当我们有多个嵌套函数时问题会很麻烦。使用箭头函数,使用“this”关键字更容易,因为箭头函数没有自己的绑定到“this”,如果在箭头函数内部访问“this”,它是从外部获取的。
var person = {
name: 'Zeep',
tasks: ['sweep the floor', 'clean the room', 'wash the dishes', 'take out the garbage'],
doing: function() {
this.tasks.forEach(task => {
console.log(this.name + " needs to " + task);
});
}
}
person.doing();
/*
Zeep needs to sweep the floor
Zeep needs to clean the room
Zeep needs to wash the dishes
Zeep needs to take out the garbage
*/
在上面的代码段中,我们看到this.name
console里面有,由于箭头函数没有自己绑定到this,它会去外面找,在这里找到doing()
属于person
Object的方法,然后this
在这种情况下,将引用person
对象。否则对于常规函数,函数this
内部总是引用一个全局对象,即窗口对象。因此,如果我们用常规函数更改箭头函数,我们会得到不同的结果:
var person = {
name: 'Zeep',
tasks: ['sweep the floor', 'clean the room', 'wash the dishes', 'take out the garbage'],
doing: function() {
this.tasks.forEach(function(task) {
// this now refers to the window object, and this.name is not specified, hence 'undefined' will be returned.
console.log(this.name + " needs to " + task);
});
}
}
person.doing();
/*
undefined needs to sweep the floor
undefined needs to clean the room
undefined needs to wash the dishes
undefined needs to take out the garbage
*/
将箭头函数仅用作函数或非对象方法时也许是有益的,但在为对象创建方法方面,箭头函数不适合:
var book = {
title: 'Thinking, Fast and Slow',
author: 'Daniel Kahneman',
display: () => {
return this.title + " is written by " + this.author;
}
}
book.display();
// undefined is written by undefined
箭头函数不能用作构造函数。它们不能用new
关键字调用。
var Book = (title, author) => {
this.title = title;
this.author = author;
}
var instance = new Book('To Kill a Mockingbird', 'Harper Lee'); // TypeError
处理事件时,this
函数内部的值应该是动态的,因此箭头函数在这种情况下并不理想。
var element = document.querySelector('.elem');
element.addEventListener('click', () => {
// this === Window
})
element.addEventListener('click', function() {
// this === element
})
箭头函数没有“参数”
在 JavaScript 中,arguments
是一个 Array
可在函数内部访问的类似对象,其中包含传递给该函数的参数值。箭头函数没有自己的“this”绑定,也没有参数对象。arguments
继承自它们的父函数,例如“this”。
// OK with regular function
var temp = function() {
var arr = Array.from(arguments);
return arr;
}
temp(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
// Not so OK with arrow function
var temp = () => {
var arr = Array.from(arguments);
return arr;
}
temp(1, 2, 3, 4, 5); // Error
数组操作中的箭头函数
现在我们已经学习了箭头函数的基本语法并看到了它的一些用例。但在大多数情况下,箭头函数通常用于通过某些方法进行数组操作,例如map()
, filter()
, reduce()
。
例如,我们有一个对象数组,我们将使用箭头函数和上面列出的一些方法来操作数组。
var fruits = [
{
name: 'pear',
price: 20
},
{
name: 'grape',
price: 15
},
{
name: 'apple',
price: 25
}
];
现在让我们获取水果的名称:
fruits.map(fruit => fruit.name);
/*
pear
grape
apple
*/
检查水果的价格大于或等于 20:
fruits.filter(fruit => fruit.price >= 20);
// [ { name: 'pear', price: 20 }, { name: 'apple', price: 25 } ]
总结一下水果的价格:
fruits.reduce((accumulator, fruit) => accumulator + fruit.price, 0); // 60
正如我们所看到的,在这种情况下使用箭头函数使代码看起来非常清晰和简洁。
带有回调和Promise的箭头函数
在使用异步或 Promise 时,使用传统 ES5 的代码通常包含许多函数和返回关键字。因此,异步代码也是使用箭头函数使代码更简洁易读的好地方。这是一个在 ES5 中链接承诺的简单示例:
aAsync()
.then(function () { return bAsync(); })
.then(function () { return cAsync(); })
.done(function () { finish(); });
使用 ES6,上面的这段代码可以翻译成更短更简洁的版本:
Async().then(() => bAsync()).then(() => (Async()).done(() => finish);
什么时候不应该使用箭头函数
箭头函数通常非常棒,但我们仍然不能完全用箭头函数代替常规函数。如前所述,总结一下,有些情况下你不应该使用箭头函数:
- 对象方法
- DOM 事件
- 原型方法
- 当您需要使用参数对象时
如果您愿意,可以在所有其他场合使用箭头功能。
总结起来
总的来说,箭头函数是 ES6 最受青睐的特性之一,在箭头函数的帮助下,你的代码可以看起来更加整洁和简洁。此类函数通常用于数组操作、异步代码和许多其他场景。在某些情况下它不能代替常规功能。它没有this
, argument
, 不能作为构造函数工作,并且使用 new 关键字调用它会发生错误。