Safari中条件语句混用函数与const/let触发ReferenceError问题咨询
问题解答:Safari 11中块级函数与const作用域的兼容性问题
你的观察非常准确,Safari 11的这个行为完全符合当时的ECMAScript规范版本,背后是ES6规范演进过程中关于块级函数声明的规则变化导致的浏览器实现差异。下面详细拆解:
核心原因:ES6规范对块级函数声明的规则调整
在ES5及更早版本中,函数声明只能存在于全局作用域或函数作用域,块级作用域(比如if、for块)内的函数声明属于语法错误(虽然多数浏览器会宽松处理)。ES6引入let/const后正式定义了块级作用域,但对于块内函数声明的行为,规范经历了两次关键调整:
- 早期ES2015(ES6)规范:
- 非严格模式下:块内的函数声明会被提升到包含该块的函数作用域或全局作用域顶部,而不是被限制在块级作用域内;
- 严格模式下:块内函数声明会被限制在当前块级作用域内,和
let/const的作用域规则一致。
- ES2016及之后的规范修订:
- 调整了非严格模式下的行为,让块内函数声明也被限制在块级作用域内,和
let的表现对齐,以此减少兼容性混乱。
- 调整了非严格模式下的行为,让块内函数声明也被限制在块级作用域内,和
对应你的代码场景
你的代码:
if(true) { const a = 1; function myFunc() { alert(a); } myFunc(); }
- 在Chrome/Firefox中:它们提前实现了ES2016修订后的规范,非严格模式下也会把
myFunc限制在if块的作用域内,所以能正常访问同块内的const a; - 在Safari 11中:它遵循的是早期ES2015规范,非严格模式下
myFunc被提升到全局作用域,而const a是块级作用域的变量,全局作用域的myFunc无法访问块内的a,因此抛出ReferenceError; - 启用严格模式后:Safari 11会按照早期规范中严格模式的规则,把
myFunc限制在块级作用域内,和const a同作用域,因此能正常运行。
官方规范的相关说明
ECMAScript规范的修订历史中明确记录了这个变化:
- 早期ES2015规范(ECMA-262 6th Edition)的13.3.1节定义了非严格模式下块内函数声明的提升规则;
- ES2016及后续版本的规范修改了这一规则,让非严格模式下的块内函数声明也绑定到块级作用域。
由于caniuse和MDN的文档更侧重当前主流规范的行为,对于这种旧版规范的过渡性差异记录较少,但你可以在ECMA官方的规范修订历史文档中找到相关细节。
总结与解决方案
Safari 11的行为是符合它所实现的早期ES6规范的,并非浏览器bug。解决这类问题的最佳实践就是始终启用严格模式(在代码顶部添加'use strict';),它不仅能让块内函数的作用域行为在各浏览器中保持一致,还能避免很多其他兼容性陷阱和潜在的代码问题。
内容的提问来源于stack exchange,提问作者Luca Rainone
相关产品推荐
相关产品推荐

