阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 函数声明与函数表达式

函数声明与函数表达式

作者:陈川 阅读数:61786人阅读 分类: JavaScript

在JavaScript中,函数可以通过两种主要方式定义:函数声明和函数表达式。两者在语法、作用域提升和执行时机上存在差异,理解这些差异对编写高效、可维护的代码至关重要。

函数声明的基本语法

函数声明以function关键字开头,后跟函数名和一对圆括号。函数体包裹在花括号中。例如:

function greet(name) {
  return `Hello, ${name}!`;
}

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

console.log(greet('Alice')); // 输出: Hello, Alice!

function greet(name) {
  return `Hello, ${name}!`;
}

函数表达式的基本语法

函数表达式将函数赋值给变量或属性。它可以是匿名的,也可以有名称:

const greet = function(name) {
  return `Hello, ${name}!`;
};

与函数声明不同,函数表达式不会被提升。以下代码会抛出错误:

console.log(greet('Alice')); // TypeError: greet is not a function

const greet = function(name) {
  return `Hello, ${name}!`;
};

具名函数表达式

函数表达式可以包含名称,这在调试时很有用:

const factorial = function calcFactorial(n) {
  return n <= 1 ? 1 : n * calcFactorial(n - 1);
};

名称calcFactorial只在函数内部可见,外部作用域无法访问:

console.log(factorial(5)); // 120
console.log(calcFactorial); // ReferenceError

箭头函数表达式

ES6引入的箭头函数是函数表达式的简洁形式:

const greet = name => `Hello, ${name}!`;

箭头函数没有自己的this绑定,适合用作回调:

const obj = {
  values: [1, 2, 3],
  double: function() {
    return this.values.map(v => v * 2); // 正确继承this
  }
};

IIFE模式

立即调用函数表达式(IIFE)可以创建私有作用域:

(function() {
  const privateVar = 'secret';
  console.log(privateVar); // 'secret'
})();

console.log(privateVar); // ReferenceError

函数声明与表达式的选择

需要提升功能时使用函数声明:

// 允许提前调用
setupEventListeners();

function setupEventListeners() {
  // 事件处理逻辑
}

需要控制函数创建时机时使用表达式:

let logger;

if (debugMode) {
  logger = function(message) {
    console.debug(message);
  };
} else {
  logger = function() {}; // 空函数
}

函数作为参数传递

函数表达式常用于高阶函数:

const numbers = [1, 2, 3];
const doubled = numbers.map(function(n) {
  return n * 2;
});

箭头函数使这种场景更简洁:

const tripled = numbers.map(n => n * 3);

构造函数中的差异

函数声明不能直接用作构造函数:

function Person(name) {
  this.name = name;
}
const bob = new Person('Bob');

而函数表达式赋值给变量后同样可用作构造函数:

const Animal = function(species) {
  this.species = species;
};
const cat = new Animal('Felis catus');

递归实现的对比

函数声明在递归调用中更直观:

function fibonacci(n) {
  return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

函数表达式需要确保变量已声明:

const fibonacci = function(n) {
  return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

模块模式中的应用

函数表达式支持灵活的模块定义:

const counterModule = (function() {
  let count = 0;

  return {
    increment: function() {
      return ++count;
    },
    reset: function() {
      count = 0;
    }
  };
})();

性能考量

现代JavaScript引擎对两种形式的优化已无显著差异,但函数声明因提升特性可能在解析阶段稍快:

// 引擎会优先处理函数声明
function heavyComputation() {
  // 复杂计算
}

调试时的可读性

具名函数在调用栈中显示更清晰:

// 函数声明
function fetchData() {
  throw new Error('Network issue');
}

// 调用栈显示fetchData
fetchData();

// 匿名函数表达式
const fetchData = function() {
  throw new Error('Network issue');
};

// 调用栈显示anonymous function
fetchData();

动态函数生成

函数表达式支持运行时动态创建:

function createMultiplier(factor) {
  return function(x) {
    return x * factor;
  };
}

const double = createMultiplier(2);
console.log(double(5)); // 10

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:严格模式

下一篇:对象枚举与迭代

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌