如何在javascript中定义和调用函数?_函数表达式和函数声明有何不同?【教程】

函数声明整体提升且必须有名,可提前调用;函数表达式仅变量名提升(var)或不提升(let/const),须赋值后调用,匿名时调试困难。

函数声明和函数表达式都能定义可调用的函数,但提升(hoisting)行为、语法位置、命名调试支持完全不同——选错可能让你在 undefinedReferenceError 里卡住几分钟。

函数声明:能被提前访问,必须有名字

函数声明会整体被提升到当前

作用域顶部,所以可以在定义前调用。它必须带标识符名,不能作为表达式的一部分直接使用。

  • function greet(name) { return 'Hello, ' + name; } 是合法声明
  • greet('Alice'); 在声明前写也不会报错(会被提升)
  • 不能写成 if (true) { function foo() {} } —— 大多数引擎允许但属非标准行为,不同环境表现不一致
  • 在调试器中显示为 greet,堆栈跟踪清晰

函数表达式:只提升变量名,不提升函数体

把函数赋给变量时,属于函数表达式。只有 var 声明的变量名会被提升,函数体不会;let/const 则完全不提升,访问会触发暂时性死区(TDZ)。

  • const add = function(a, b) { return a + b; }; —— add 是变量名,函数是匿名表达式
  • add(2, 3); 必须在赋值之后执行,否则 TypeError: add is not a functionvar 下是 undefinedlet/const 下是 ReferenceError
  • 可以写具名函数表达式:const factorial = function fact(n) { return n —— 名字 fact 只在内部可用,利于递归和调试
  • 在 Chrome DevTools 堆栈中可能显示为 (anonymous),除非用了具名形式

箭头函数不是替代品,而是不同语义

箭头函数没有自己的 thisargumentssupernew.target,也不能用作构造函数。它本质是更紧凑的函数表达式语法,不是声明或表达式的“第三种类型”。

  • const multiply = (x, y) => x * y; 等价于 const multiply = function(x, y) { return x * y; };
  • obj.method = () => { console.log(this); }; 中的 this 指向外层作用域,不是 obj
  • 不能用 new multiply(),会抛 TypeError: multiply is not a constructor
  • 没有 prototype 属性,multiply.prototypeundefined

真正容易被忽略的是:函数名是否出现在调用栈、是否能被递归引用、是否参与作用域提升——这些不是风格偏好,而是运行时行为差异。调试时看到 at 却找不到源头?先检查你用的是不是无名函数表达式。