可能你已经知道有好几种方式来编写一个函数。我们整天都会编写诸如function doStuff() {}
() => {}
这样的代码。但是你知道它们之间的差异或者为什么使用特定的方式来编写函数吗?
注意:所有例子都使用 javascript 来编写。
差异一:name
当你创建一个具名函数,这就是函数声明。函数表达式可以省略 name,使之成为匿名函数。
函数声明
function doStuff() {}
复制代码
函数表达式
const doStuff = function() {};
复制代码
或者 ES6 中新增的箭头函数:
const doStuff = () => {};
复制代码
提升
提升表示你的函数和变量可以在作用域一开始的部分就能被使用,而不是仅在它们被创建之后。它们在编译时初始化,在文件中的任何位置使用。
译者:结合下面的代码可以更好的理解提升的概念。
foo(); // hello
function foo() {
console.log('hello');
}
console.log(num); // undefined
var num = 1;
console.log(num); // 1
复制代码
函数声明存在提升而函数表达式不会。
举例更容易说明问题:
doStuff();
function doStuff() {}
复制代码
上面的代码能正常运行,但下面的代码不会:
doStuff();
const doStuff = () => {};
复制代码
使用函数表达式的情况
看起来好像因为函数声明的提升特性,让函数表达式变得没有什么用处了。但是需要考虑函数会在何时何地被使用才能决定使用声明或者表达式。
函数表达式可以有效的避免污染全局作用域。比起你的代码中充斥着各种各样的具名函数,匿名函数可以让你使用后立即丢弃掉。
IIFE
立即执行的函数表达式。从名字就可以知道它的作用了。函数同时被创建和调用,你可以这样使用 IIFE:
(function() => {})();
复制代码
或者
(() => {})();
复制代码
如果想深入了解,可以查看这篇文章。
回调函数
作为参数传入其他函数的函数通常被称为回调函数。例子:
function mapAction(item) {
// do stuff to an item
}
array.map(mapAction);
复制代码
这里的问题是mapAction
会在你整个程序中都可用——但这没有必要。如果是一个函数表达式,它在使用它的函数之外就不可用了。
array.map(item => { //do stuff to an item })
复制代码
或者
const mapAction = function(item) {
// do stuff to an item
};
array.map(mapAction);
复制代码
当然这里的mapAction
在初始化它的代码之后仍然可用。
小结
**简单地说,如果你想在让函数全局通用,在全局作用域上使用函数声明创建函数。**使用函数表达式限制函数的可用范围,保持全局作用域不被污染,也让代码更为简洁。
参考
- Function declaration, MDN docs.
- Function expression, MDN docs.
- Hoisting, MDN glossary.