JavaScript中创建函数有两种不同的方式。函数声明这种方式已经使用很久了,但慢慢的被函数表达式这种方式在替代。
//函数声明式
function funcDeclaration() {
return 'A function declaration';
}
//函数表达式
var funcExpression = function () {
return 'A function expression';
}
声明和表达式之间的差异
类似于var
声明,函数声明可以提升到其他代码之前,但函数表达式不能提到其他代码之前,但它允许保留在本地变量范围内。
通常函数声明和函数表达式是可以相互互换使用,但有时函数表达式结果理解代码不需要一个临时的函数名。
扩展阅读
- JavaScript 函数声明和函数表达式的区别
- 函数声明 VS 函数表达式
- 深入理解JavaScript系列(2):揭秘命名函数表达式
- 详解Javascript 函数声明和函数表达式的区别
- Function Declarations vs. Function Expressions
- Javascript function declarations vs function operators
函数表达式的好处
函数表达式比函数声明式有几个更加有用的地方:
- 是一个闭包
- 可以作为其他函数的参数
- 可以立即调用函数表达式(IIFE)
创建闭包
闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。
function tabsHandler(index) {
return function tabClickEvent(evt) {
// 制作tab
// 可以从内部访问index变量.
};
}
var tabs = document.querySelectorAll('.tab'),
i;
for (i = 0; i < tabs.length; i += 1) {
tabs[index].onclick = tabsHandler(i);
}
附加事件在循环后处理程序,所以一个闭包需要记住for
中一个适当的值。
// 不好的代码,说明doSomething为什么需要闭包
var i;
for (i = 0; i < list.length; i += 1) {
document.querySelector('#item' + i).onclick = function doSomething(evt) {
// #item(i)做什么
// 但是,这个函数执行时,i总是得到list.length的值
}
}
很容易理解,通过for
执行doSomething()
函数会发生什么问题。
// 不好的代码,说明doSomething为什么需要闭包
var list = document.querySelectorAll('.item'),
i,
doSomething = function (evt) {
// #item(i)做什么
// 但是,这个函数执行时,i的值不在循环内
};
for (i = 0; i < list.length; i += 1) {
item[i].onclick = doSomething;
}
这里的解决方案是通过index
作为函数参数传递给一个外部函数,以便将该值传递给一个内部函数。你通常会看到通过return
一个函数来处理:
// 以下代码展示了一个闭包
var list = ['item1', 'item2', 'item3'],
i,
doSomethingHandler = function (itemIndex) {
return function doSomething(evt) {
// 现在doSomething函数可以通过 index变量来访问itemIndex参数
// 以及其他变理也是可用的
console.log('Doing something with ' + list[itemIndex]);
};
};
for (i = 0; i < list.length; i += 1) {
list[i].onclick = doSomethingHandler(i);
}
在这个FAQ示例中可以帮助你更好的理解闭包。
扩展阅读
- 理解Javascript的闭包
- 详解js闭包
- 闭包
- 学习Javascript闭包(Closure)
- 闭包,懂不懂由你,反正我是懂了
- JavaScript 闭包详解
- JavaScript 之闭包与高阶函数(一)
- JavaScript中的闭包
- 理解 JavaScript 闭包
- Closures in JavaScript
- Master the JavaScript Interview: What is a Closure?
作为参数传递
函数表达式可以作为参数直接传递给函数,而没有必要赋值到另一个临时变量上。
在jQuery中,他们常以一个匿名函数的形式出现,如:
$(document).ready(function () {
console.log('An anonymous function');
});
还可以使用类似forEach()
方法,使用一个处理数组项的函数表达式传给forEach()
。它们也不是匿名函数。给函数表达式命名是为了更好的知道表达函数应该做什么,也更好的帮助调试代码:
var productIds = ['12356', '13771', '15492'];
productIds.forEach(function showProduct(productId) {
...
});
立即调用函数表达式(IIFE)
IIFE是用来防止你的函数和变量影响全局变量。匿名函数作用域内的所有属性。这是一种常见的设计模式,用来防止代码产生不必要的副作用。
也利于代码块维护,有关于这方面更深入的介绍,可以阅读这篇文章。
下面是有关于IIFE的一个简单示例:
(function () {
// code in here
}());
作为一个模块使用时,更易于维护你的代码:
var myModule = (function () {
var privateMethod = function () {
console.log('A private method');
},
someMethod = function () {
console.log('A public method');
},
anotherMethod = function () {
console.log('Another public method');
};
return {
someMethod: someMethod,
anotherMethod: anotherMethod
};
}());
扩展阅读
- JS Immediately Invoked Function Expressions
- JAVASCRIPT FUNCTIONS PART 4 – IMMEDIATELY INVOKED FUNCTION EXPRESSION [IIFE]
- 深入理解JavaScript系列(4):立即调用的函数表达式
- [译] JavaScript:立即执行函数表达式(IIFE)
- Disassembling JavaScript's IIFE Syntax
- Immediately Invoked Function Expressions (aka IIFE)
- 揭秘 IIFE 语法
- 详解javascript立即执行函数表达式(IIFE)
总结
正如我们所看到的,在代码中更多的使用函数表达式来实现函数声明式功能,这样使用你的代码更简洁,更易维护。函数表达多被广大的开发人员使用,也是开发中的一个重要组成部分。如果你在开发中碰到有关于函数表达式一些有意思的东西,欢迎在评论里与我们一起分享。
本文根据@Paul Wilkins的《》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.sitepoint.com/function-expressions-vs-declarations/。
如需转载,烦请注明出处:http://www.w3cplus.com/javascript/function-expressions-vs-declarations.html