返回

JS 中函数表达式和函数声明的真相

前端

JavaScript 中的函数表达式和函数声明是定义函数的两种主要方式。它们之间存在一些关键差异,包括声明提升、作用域和闭包行为。本文将深入探讨这些差异,帮助您更好地理解 JavaScript 中的函数。

声明提升

函数声明会在脚本执行之前提升到脚本顶部。这意味着可以在声明函数之前调用它。这是因为 JavaScript 引擎在执行脚本之前会先扫描整个脚本,并将所有函数声明提升到顶部。函数表达式不会提升,因此必须在声明之前定义它。

// 函数声明
function sayHello() {
  console.log("Hello!");
}

// 函数表达式
const sayGoodbye = function() {
  console.log("Goodbye!");
};

sayHello(); // "Hello!"
sayGoodbye(); // "Goodbye!"

在上面的示例中,函数声明 sayHello() 在执行脚本之前提升到顶部,因此可以在声明之前调用它。函数表达式 sayGoodbye() 不会提升,因此必须在声明之前定义它。

作用域

函数的作用域是指函数可以访问的变量的集合。函数的作用域由其所在的位置决定。函数声明的作用域是整个脚本,而函数表达式的作用域是它所在的花括号块。

// 函数声明
function sayHello() {
  var message = "Hello!";
  console.log(message);
}

// 函数表达式
const sayGoodbye = function() {
  var message = "Goodbye!";
  console.log(message);
};

sayHello(); // "Hello!"
sayGoodbye(); // "Goodbye!"

console.log(message); // ReferenceError: message is not defined

在上面的示例中,函数声明 sayHello() 的作用域是整个脚本,因此它可以访问变量 message。函数表达式 sayGoodbye() 的作用域是它所在的花括号块,因此它只能访问变量 message。当在函数表达式外部尝试访问变量 message 时,会抛出 ReferenceError。

闭包

闭包是指可以访问其创建函数中声明的变量的函数。闭包可以用来创建一个私有变量,或者在函数执行之后仍然可以访问变量。

function createCounter() {
  var counter = 0;

  return function() {
    return ++counter;
  };
}

const counter = createCounter();

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

在上面的示例中,函数 createCounter() 返回一个函数,该函数可以访问变量 counter。这意味着该函数是一个闭包。当调用函数 counter() 时,它会返回变量 counter 的当前值,然后将 counter 的值加一。

结论

函数表达式和函数声明是 JavaScript 中定义函数的两种主要方式。它们之间存在一些关键差异,包括声明提升、作用域和闭包行为。了解这些差异对于理解 JavaScript 中的函数非常重要。