函数表达式需用“const/let/var 变量名 = function [名称](参数) { }”形式,不可提升,匿名合法;与函数声明相比,后者会提升且必须有名字,二者同名时声明优先覆盖表达式。

函数表达式怎么写,和函数声明有啥区别
函数表达式必须带 function 关键字,且不能省略函数名(除非你明确要写匿名函数)。但注意:函数表达式本身可以是匿名的——也就是不写名字,只保留 function() { ... } 这部分,然后立刻赋值给变量。
常见错误是把它写成 function() { return 42; }(); 却没赋值,结果函数执行完就丢掉了;或者误以为它能被提升(hoist),其实不会——在声明前调用会报 ReferenceError: xxx is not defined。
- 必须用
=显式赋值给变量,比如const add = function(a, b) { return a + b; }; - 函数名可省略(即匿名),但不能加标识符后又不赋值,否则语法报错
- 箭头函数本质也是函数表达式,但没有
arguments、不能用new、this行为不同
为什么变量名不能和函数名重复(即使匿名)
你写 const fn = function fn() { }; 是合法的,这时内部可递归调用 fn();但若写成 const fn = function fn() { fn(); }; 再把外层 fn 重新赋值,内部 fn 仍指向原函数——因为函数内部的 fn 是词法绑定的,不是变量查找。
更常见的坑是:用 var fn = function() { }; 然后在同一作用域再写 function fn() { },后者会被提升并覆盖前者,但只在非严格模式下生效,行为不稳定。
- 避免混用
var声明 + 函数表达式,容易触发变量提升干扰 - 命名函数表达式里的名字只在函数体内可见,对外不可访问
- 调试时堆栈里显示的是那个内部名字(如
fn),不是变量名,这点影响排查
赋值后还能改函数体吗
不能直接“修改”函数体,但可以重新赋值变量。比如 let handler = function() { console.log('v1'); }; 后续可写 handler = function() { console.log('v2'); }; ——这是完全合法的,尤其适合事件处理器或策略切换。
不过要注意:如果该函数已被其他地方闭包引用或作为参数传入,重赋值不会影响那些旧引用。这也是函数表达式比函数声明更灵活的地方。
- 用
const声明变量时,只能赋值一次,但函数体本身不可变是 JS 的天然限制,不是 const 的功劳 - 若需动态行为,优先考虑在函数体内用条件分支,而非频繁重赋值
- 重赋值对性能无实质影响,V8 等引擎已对此优化多年
Node.js 和浏览器里有啥兼容性差异
基本没有。函数表达式是 ES3 就支持的语法,所有环境都稳定运行。唯一要注意的是模块作用域:在 Node.js 的 CommonJS 模块中,顶层 function 声明会变成模块私有,但函数表达式赋值给 module.exports 才能导出。
例如:module.exports = function greet(name) { return `Hi ${name}`; }; 是标准做法;而 function greet() { } 单独写,不导出,外部就拿不到。
- ESM(
import/export)中同理,必须显式export const fn = function() { }; - IE8 及更老版本不支持命名函数表达式中的名字绑定(即
function fn() { fn(); }会报错),但现代项目基本不用考虑 - 压缩工具(如 Terser)可能把命名函数表达式的内部名删掉,影响调试,可通过配置保留










