Menu Close

JavaScript 函数声明(Function Declaration)和函数表达式(Function Expression)有什么区别?

JavaScript 中,函数表达式(Function Expression) 和 函数声明 (Function Declaration) 都可以用来定义函数,但它们有一些重要的区别:

JavaScript 函数声明(Function Declaration)和函数表达式(Function Expression)有什么区别?
JavaScript 函数声明(Function Declaration)和函数表达式(Function Expression)有什么区别?

语法区别

Function Declaration(函数声明):

function functionName() {
    // function body
}

这是最常见的定义函数的方式,函数名称是显式指定的。作为独立语句在主代码流程中声明的函数。例如:

// Function Declaration
function sum(a, b) {
  return a + b;
}

Function Expression(函数表达式):

const functionName = function() {
    // function body
};

这种方式通过将函数赋值给一个变量来定义函数,函数可以是匿名的(没有名字),也可以是具名的。在表达式内部或其他语法结构内部创建的函数。函数是在“赋值表达式”=`的右侧创建的,例如:

// Function Expression
let sum = function(a, b) {
  return a + b;
};

 提升(Hoisting)

Function Declaration:函数声明会被提升到所在作用域的顶部,意味着可以在声明之前调用函数。

例如,全局函数声明在整个脚本中都是可见的,无论它位于何处。

这是由于内部算法的原因。当 JavaScript 准备运行脚本时,它首先会在其中寻找全局的函数声明,并创建这些函数。我们可以把它想象成一个“初始化阶段”。

在处理完所有函数声明之后,代码才开始执行。因此可以访问到这些函数。

sayHi("John"); // Hello, John

function sayHi(name) {
  alert( `Hello, ${name}` );
}

函数声明 sayHi 是在 JavaScript 准备开始执行脚本时创建的,并且在整个脚本中都是可见的。

……如果它是一个函数表达式,那就不会生效了:

Function Expression:函数表达式不会被提升,只有在代码执行到那一行时,函数才会被定义。因此,必须先定义后调用。一旦执行流程到达赋值表达式右侧,例如 let sum = function… —— 就在这里,函数被创建了,并且从此刻起可以使用(赋值、调用等)。

sayHi("John"); // error!

let sayHi = function(name) {  // (*) no magic any more
  alert( `Hello, ${name}` );
};

函数表达式是在执行流程运行到它们时才被创建的。这只会在标记为(*)的那一行发生。太晚了。

匿名 vs 命名

  • Function Declaration:函数是具名的,即函数的名称是显式声明的。

  • Function Expression:函数可以是匿名的(如上例),但也可以是具名的。

    const greet = function greetFunction() {
        console.log("Hello");
    };
    

块作用域(Block Scope)

Function Declaration:在函数声明的作用域内,函数会立刻可用(因为它是提升的),可以在声明之前引用。在严格模式下,当一个函数声明出现在代码块中时,它在整个块内部都是可见的,但在块外部不可见。

Function Expression:函数表达式中的函数只有在表达式执行后才有效,因此它会受限于其所在的作用域,必须在定义之后才能使用。

例如,假设我们需要根据在运行时获得的 age 变量来声明一个 welcome() 函数,然后稍后再使用它。

如果我们使用函数声明,那么它不会按预期工作:

let age = prompt("What is your age?", 18);

// conditionally declare a function
if (age < 18) {

  function welcome() {
    alert("Hello!");
  }

} else {

  function welcome() {
    alert("Greetings!");
  }

}

// ...use it later
welcome(); // Error: welcome is not defined

这是因为函数声明只在其所在的代码块内部可见。

这里有另一个例子:

let age = 16; // take 16 as an example

if (age < 18) {
  welcome();               // \   (runs)
                           //  |
  function welcome() {     //  |
    alert("Hello!");       //  |  Function Declaration is available
  }                        //  |  everywhere in the block where it's declared
                           //  |
  welcome();               // /   (runs)

} else {

  function welcome() {
    alert("Greetings!");
  }
}

// Here we're out of curly braces,
// so we can not see Function Declarations made inside of them.

welcome(); // Error: welcome is not defined

我们该如何让 welcomeif 外部也可见呢?

正确的方法是使用函数表达式(Function Expression),并将 welcome 赋值给一个在 if 外部声明、具有适当可见性的变量。

这段代码能按预期工作:

let age = prompt("What is your age?", 18);

let welcome;

if (age < 18) {

  welcome = function() {
    alert("Hello!");
  };

} else {

  welcome = function() {
    alert("Greetings!");
  };

}

welcome(); // ok now

或者我们可以使用问号运算符 ?: 进一步简化它:

let age = prompt("What is your age?", 18);

let welcome = (age < 18) ?
  function() { alert("Hello!"); } :
  function() { alert("Greetings!"); };

welcome(); // ok now

用于回调函数和事件处理

  • Function Expression:通常用于回调函数或匿名函数的传递,因为它可以直接作为值传递给其他函数。

    setTimeout(function() {
        console.log("This is a callback function.");
    }, 1000);
    

选择函数声明还是选择函数表达式?

通常来说,当我们需要声明一个函数时,首先应该考虑使用函数声明的语法。因为这样可以更自由地组织代码,我们可以在函数声明之前就调用它们。

READ  JavaScript 的基本特性

这对于可读性也更好,因为在代码中查找 function f(…) {…} 要比 let f = function(…) {…}; 更容易。函数声明更“醒目”。

……但是,如果由于某些原因函数声明不适合我们,或者需要条件式声明(我们刚刚看过一个例子),那么应该使用函数表达式。

总结

  • 函数是值。它们可以在代码的任何位置被赋值、复制或声明。

  • 如果函数作为主代码流程中的独立语句声明,那就是“函数声明”(Function Declaration)。

  • 如果函数作为表达式的一部分创建,那就是“函数表达式”(Function Expression)。

  • 函数声明在代码块执行之前会被处理,并且在整个代码块中都可见。

  • 函数表达式在执行流程到达它们时才会被创建。

在大多数情况下,当我们需要声明一个函数时,函数声明是更可取的,因为它在声明之前就可见。这为代码组织提供了更多的灵活性,并且通常更具可读性。

因此,只有当函数声明不适合某个任务时,我们才应该使用函数表达式。在本章中我们已经看过一些例子,未来还会看到更多。

除教程外,本网站大部分文章来自互联网,如果有内容冒犯到你,请联系我们删除!
Posted in JavaScript 基础

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Leave the field below empty!