函数声明整体提升且必须有名,可提前调用;函数表达式仅变量名提升(var)或不提升(let/const),须赋值后调用,匿名时调试困难。
函数声明和函数表达式都能定义可调用的函数,但提升(hoisting)行为、语法位置、命名调试支持完全不同——选错可能让你在 undefined 或 ReferenceError 里卡住几分钟。
函数声明会整体被提升到当前作用域顶部,所以可以在定义前调用。它必须带标识符名,不能作为表达式的一部分直接使用。
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 function(var 下是 undefined,let/const 下是 ReferenceError)const factorial = function fact(n) { return n —— 名字 fact 只在内部可用,利于递归和调试
(anonymous),除非用了具名形式箭头函数没有自己的 this、arguments、super 或 new.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.prototype 是 undefined
真正容易被

at 却找不到源头?先检查你用的是不是无名函数表达式。