0 前言:本菜鸟在学习《你不知道的JavaScrip》一书中,发现如下代码:
foo(); // "b"
var a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
书中给出的代码结果即为 `// 'b'`。
测试1: 然而我自己测试发现上述代码直接报错:`TypeError: foo is not a function`
在node环境(v14.19.1)和 浏览器环境(chrome 107.0.5304.89(正式版本) (64 位))都是 上述错误。
测试2:当我们把 foo() 放到代码末尾时, 打印的是 a。
var a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
foo(); // "a"
测试3 :(函数声明、和 函数表达式的不同)
foo1()
function foo1() {// 声明式函数,无论foo1() 放在哪,都正常执行
console.log('foo1'); //foo1
}
foo1()
foo1() // 执行语法放在函数表达式前面,报错:TypeError: foo1 is not a function
var foo1 = function () { //函数表达式
console.log('foo1');
}
foo1() // 执行语法放在函数表达式后面,代码正常执行,打印:'foo1'
1. 据此,以下为本菜鸟的分析,如有不对,欢迎大神指正:
分析1:(据书给出的结果)
a 假如书中给出的代码运行正常且 foo() 打印的指为 `// 'b'`,
b1 那么说明 if 语句没有自己块级作用域,上述代码整个即为全局作用域,且第二个 foo 函数声明覆盖了第二个 foo 函数声明。
b2 如果 if 和 else 两个 {} 块级作用域是指未一个块级作用域,也会出现后者覆盖前者。但是仍旧处于块级作用域中,不会泄漏到全局。foo() 仍旧会报错。
c 因此,假设数中结果成立,那么说明 if 和 else 中的两个 foo 函数声明都会在全局作用域中,且 后者对前者覆盖了,所以最后结果打印了 b;
分析2:(根据 书给出的结果和测试1的结果)
a 在本菜鸟的测试1中,上述代码运行结果是 `TypeError: foo is not a function`
b 因为错误结果是 TypeError 而不是 ReferenceError,说明引擎编译时发生了LHS错误而不是RHS错误。即函数 foo() 声明被提升了,作用找到了foo(),但是在赋值时即LHS时发生了错误。
c 那这是否说明 if 语句没有块级作用域。但是如果没有块级作用域,那么结果应该同书中所描述的,而不是报错。
d 假如有块级作用域,那么 if 语句块级内的函数声明不应该不会泄漏到全局吗?那么错误内容应该是 ReferenceError 啊! 此时的 if 语句更像是半个块级作用域,它把`声明式函数` 的行为模式(函数在作用域内的提升) 变成了 `函数表达式`?
e 脑子一片混乱,期待大神解答。
分析3:(加上测试2 的结果)
a 重新理了一下思路,如果按照分析2 - d 的结论接着测试。
b 将 foo() 放在代码末尾,发现此时语句运行成功。且打印结果是 代码所预期的且可以被判断语句控制时的结果('a')。
c 此时 if 语句的作用域似乎也可以验证分析 2 得出的结论,“半个块级作用域,其将`函数声明`的行为模式变为`函数表达式`“。
2.结尾
a 书中后续也写了这么一句话:“但是需要注意这个行为并不可靠,在 JavaScript 未来的版本中有可能发生改变,因此应该 尽可能避免在块内部声明函数。”
b 有大佬帮本菜鸟分析一波我这思考思路错在哪了吗?或者说JavaScript本身已经改变了什么?