关键在于三个可验证观察点:提升时机(块内声明前是否为undefined)、作用域可见性(块外能否访问)、执行时是否报错;Chrome/Firefox新版本输出"outer"且块内log为undefined,IE10输出"inner"且块内log为function,严格模式下可能TypeError。

识别块级作用域中 function 声明在不同浏览器中的行为偏差,关键不在于死记版本号,而在于抓住三个可验证的观察点:提升时机、作用域可见性、执行时是否报错。下面从实操角度给出清晰判断路径。
看函数是否在块外被访问到
这是最直接的区分方式。写一段带条件块的代码,在块外调用该函数:
function f() { console.log('outer'); }
{
if (false) {
function f() { console.log('inner'); }
}
}
f(); // 这里会输出什么?是否报错?
结果对比:
- Chrome(v80+)、Firefox(v78+)、Safari(v14+):执行成功,输出
"outer"(ES6附录B兼容实现,函数声明只提升到块头部,但不污染外层) - IE10 及更早:输出
"inner"(旧引擎无视块级作用域,函数声明被完全提升并覆盖) - 严格模式下 Chrome/Firefox:可能直接报
TypeError: f is not a function(因块内函数未被提升到外层,且外层无定义)
检查块内声明前能否访问函数
在 if 或 {} 块开头就 console.log(f),看是否为 undefined、函数本身,还是报错:
{
console.log(f); // 此处
function f() {}
}
典型表现:
- 新浏览器(ES6+):打印
undefined(类似let,声明未初始化,存在“暂时性死区”) - 旧浏览器(IE11及以下):打印
function f(){}(函数声明被完整提升并初始化) - 注意:若用
var f = function(){}或let f = () =>{},则所有现代浏览器都统一为undefined或报错,不具区分性
验证是否允许重复声明同名函数
在同一个块内多次声明同名函数,观察是否语法错误或静默覆盖:
{
function foo() { return 1; }
function foo() { return 2; } // 这行是否触发 SyntaxError?
console.log(foo()); // 输出 1 还是 2?
}
实际差异:
- Chrome/Firefox(非严格模式):不报错,后声明覆盖前声明 → 输出
2 - 严格模式下或 Safari(某些版本):可能抛
SyntaxError: Identifier 'foo' has already been declared - IE10:不报错,按顺序覆盖,行为与非严格模式一致
用调试器快速定位(Chrome DevTools 实操建议)
在 Chrome 中打开 Sources 面板,把如下代码粘贴进控制台并断点:
console.log('start');
{
console.log(typeof f); // 断点设在这行
function f() {}
}
console.log(typeof f);
执行后查看 Scope 面板:
- 若看到
f出现在 “Block” 范围下,且值为function→ 新版行为(已进入块,完成定义) - 若只在 “Script” 或 “Function” 范围看到
f,且值为undefined→ 提升仅声明,未定义 - 若在 “Script” 下直接出现
f: function,且 Block 下无此项 → 旧引擎全局提升











