为何这段JavaScript代码先输出undefined再抛出TypeError?
示例代码
function foo() { if (true) { function bar() { console.log("bar"); } } else { function qux() { console.log("qux"); } } console.log(qux); qux(); } foo();
输出结果
undefined TypeError: qux is not a function
问题解答
为什么console.log(qux)输出undefined且未抛出ReferenceError?
这要从JavaScript的变量提升和旧引擎对块内函数声明的处理逻辑说起:
- 当你在
if/else这类块级语句里写函数声明时,引擎会把函数名(也就是qux这个标识符)提升到外层函数(foo)的作用域顶部,但不会同步提升函数定义。也就是说,foo作用域里提前存在了qux这个变量,初始值为undefined。 - 因为代码里
if (true)分支会执行,else分支完全不会进入,所以qux的函数定义从未被执行,它的值一直保持undefined。此时访问qux不会触发ReferenceError——毕竟这个变量已经存在于当前作用域中,只是没有赋值,所以console.log(qux)输出undefined。
为什么调用qux()会抛出TypeError?
qux的当前值是undefined,而undefined不属于函数类型,当你试图把它当作函数调用时,自然会抛出TypeError: qux is not a function。
函数声明提升的具体规则?
分两种场景:
- 普通函数声明(不在块级语句内):标识符会被提升到作用域顶部,并且直接初始化为对应的函数本体。比如不管
function fn() {}写在函数的顶部还是底部,调用时都能直接生效。 - 块级语句内的函数声明(ES6非严格模式):标识符会被提升到外层函数作用域,但初始值为
undefined,只有进入对应的块时,才会把函数赋值给这个标识符。如果块没有被执行,这个变量就会一直保持undefined——这就是你代码里qux的情况。
ES6严格模式下,块内的函数声明会被限制在块级作用域内,此时在块外访问qux就会抛出ReferenceError,但你的代码是非严格模式,所以遵循的是旧规则。
内容的提问来源于stack exchange,提问作者Chibi
相关产品推荐
相关产品推荐

