使用函数表达式与函数声明的时机,在 JavaScript 中创建函数有两种方法:函数表达式和函数声明。在本文中,我们将讨论何时使用函数表达式与函数声明,并解释它们之间的区别。
函数声明已经使用了很长时间,但是函数表达式已经逐渐接管了。许多开发人员不确定何时使用其中一种,因此他们最终使用了错误的一种。
函数表达式和函数声明之间存在一些关键差异。让我们仔细看看这些差异,以及何时在代码中使用函数表达式与函数声明。
unction funcDeclaration() { return 'A function declaration'; } let funcExpression = function () { return 'A function expression'; }
什么是函数声明?
函数声明是在您创建函数并为其命名时。在编写 function 关键字时声明函数的名称,后跟函数名称。例如:
function myFunction() { // do something };https://www.zuze.net/wp-admin/post-new.php#
如您所见,函数名称 ( myFunction
) 是在创建函数时声明的。这意味着您可以在函数定义之前调用它。
下面是一个函数声明的例子:
function add (a, b) { return a + b; };
什么是函数表达式?
函数表达式是当您创建一个函数并将其分配给一个变量时。该函数是匿名的,这意味着它没有名称。例如:
let myFunction = function() { // do something };
如您所见,函数已分配给myFunction
变量。这意味着您必须先定义该函数,然后才能调用它。
下面是一个函数表达式的例子:
let add = function (a, b) { return a + b; };
函数表达式和声明之间的区别
函数表达式和函数声明之间有几个关键区别:
- 函数声明被提升,而函数表达式则没有。这意味着您可以在定义函数之前调用函数声明,但不能使用函数表达式来执行此操作。
- 使用函数表达式,您可以在函数定义后立即使用它。对于函数声明,您必须等到整个脚本被解析。
- 函数表达式可以用作另一个函数的参数,但函数声明不能。
- 函数表达式可以是匿名的,而函数声明不能。
了解函数表达式中的作用域:JavaScript 提升差异
与let
语句类似,函数声明被提升到其他代码的顶部。
不提升函数表达式。这允许它们从定义它们的范围内保留局部变量的副本。
通常,您可以互换使用函数声明和函数表达式。但有时函数表达式会产生更易于理解的代码,而无需临时函数名称。
那么,什么时候应该使用函数表达式而不是函数声明呢?
答案取决于您的需要。如果您需要更灵活的函数或未提升的函数,那么函数表达式是最佳选择。如果您需要更具可读性和易懂性的函数,请使用函数声明。
如您所见,这两种语法相似。最明显的区别是函数表达式是匿名的,而函数声明有一个名字。
今天,当您需要做一些函数表达式不能做的事情时,您通常会使用函数声明。如果您不需要做任何只能通过函数声明完成的事情,那么通常最好使用函数表达式。
当您需要创建一个递归的函数,或者当您需要在定义它之前调用该函数时,请使用函数声明。根据经验,当您不需要执行任何这些操作时,使用函数表达式来获得更简洁的代码。
函数声明的好处
使用函数声明有几个主要好处。
- 它可以使您的代码更具可读性。如果你有一个长函数,给它起一个名字可以帮助你跟踪它在做什么。
- 函数声明已提升,这意味着它们在代码中定义之前就可用。如果您需要在函数定义之前使用该函数,这会有所帮助。
函数表达式的好处
函数表达式也有一些好处。
- 它们比函数声明更灵活。您可以创建函数表达式并将它们分配给不同的变量,当您需要在不同的地方使用相同的函数时,这会很有帮助。
- 函数表达式未提升,因此您不能在代码中定义它们之前使用它们。如果您想确保函数仅在定义后使用,这会有所帮助。
何时选择函数声明与函数表达式
在大多数情况下,很容易找出哪种定义函数的方法最适合您的需要。这些指南将帮助您在大多数情况下快速做出决定。
在以下情况下使用函数声明:
- 您需要一个更具可读性和易懂性的函数(例如一个长函数,或者您需要在不同地方使用的函数)
- 匿名函数不适合您的需要
- 你需要创建一个递归的函数
- 您需要在定义之前调用该函数
在以下情况下使用函数表达式:
- 你需要一个更灵活的功能
- 你需要一个没有提升的功能
- 该函数应仅在定义时使用
- 该函数是匿名的,或者不需要名称供以后使用
- 您想控制函数何时执行,使用立即调用函数表达式 (IIFE) 等技术
- 你想将函数作为参数传递给另一个函数
也就是说,在许多情况下,函数表达式的灵活性成为一种强大的资产。
解锁函数表达式:JavaScript 提升差异
有几种不同的方法可以使函数表达式变得比函数声明更有用。
- 闭包
- 其他函数的参数
- 立即调用函数表达式 (IIFE)
使用函数表达式创建闭包
当您想在函数执行之前为函数提供参数时,可以使用闭包。循环遍历NodeList
.
在函数执行后信息不可用的情况下,闭包允许您保留其他信息,例如索引。
function tabsHandler(index) { return function tabClickEvent(evt) { // Do stuff with tab. // The index variable can be accessed from within here. }; } let tabs = document.querySelectorAll('.tab'), i; for (i = 0; i < tabs.length; i += 1) { tabs[i].onclick = tabsHandler(i); }
附加的事件处理程序稍后执行(在循环完成后),因此需要一个闭包来保留for
循环的适当值。
// Bad code, demonstrating why a closure is needed let i; for (i = 0; i < list.length; i += 1) { document.querySelector('#item' + i).onclick = function doSomething(evt) { // Do something with item i // But, by the time this function executes, the value of i is always list.length } }
doSomething()
通过从for
循环中提取函数,更容易理解为什么会出现问题。
// Bad code, demonstrating why a closure is needed let list = document.querySelectorAll('.item'), i, doSomething = function (evt) { // Do something with item i. // But, by the time this function executes, the value of i is not what it was in the loop. }; for (i = 0; i < list.length; i += 1) { item[i].onclick = doSomething; }
这里的解决方案是将索引作为函数参数传递给外部函数,以便它可以将该值传递给内部函数。您通常会看到用于组织内部返回函数所需信息的处理函数。
// The following is good code, demonstrating the use of a closure let list = ['item1', 'item2', 'item3'], i, doSomethingHandler = function (itemIndex) { return function doSomething(evt) { // now this doSomething function can retain knowledge of // the index variable via the itemIndex parameter, // along with other variables that may be available too. console.log('Doing something with ' + list[itemIndex]); }; }; for (i = 0; i < list.length; i += 1) { list[i].onclick = doSomethingHandler(i); }
了解有关闭包及其用法的更多信息。 将函数表达式作为参数传递 函数表达式可以直接传递给函数,而不必分配给中间临时变量。 您最常以匿名函数的形式看到它们。下面是一个熟悉的 jQuery 函数表达式示例:
$(document).ready(function () { console.log('An anonymous function'); });
函数表达式也用于在使用诸如forEach()
.
它们也不必是未命名的匿名函数。为函数表达式命名以帮助表达函数应该做什么并帮助调试是个好主意:
let productIds = ['12356', '13771', '15492']; productIds.forEach(function showProduct(productId) { ... });
立即调用函数表达式 (IIFE)
IIFE 有助于防止您的函数和变量影响全局范围。
其中的所有属性都在匿名函数的范围内。这是一种常见的设计模式,用于防止您的代码在其他地方产生不需要或不需要的副作用。
它还用作模块模式,以在易于维护的部分中包含代码块。我们在揭秘 JavaScript 闭包、回调和 IIFE中更深入地研究了这些。
下面是一个 IIFE 的简单示例:
(function () { // code in here }());
…当用作模块时,可以为您的代码带来一些易于实现的可维护性。
let myModule = (function () { let 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 }; }());
结论
正如我们所见,函数表达式与函数声明并没有根本不同,但它们通常可以产生更清晰、更易读的代码。