如何解决条件语句中的混合函数和const / let导致Safari中的ReferenceError 标准语义学旧版网络语义
我们有这样的东西
if(true) {
const a = 1;
function myFunc() {
alert(a);
}
myFunc();
}
在Safari 11中,这导致"ReferenceError: Can't find variable: a"
。
相同的代码在Chrome和Firefox中正常运行。
在Safari中使用"strict mode"
解决了该问题。
我认为主要问题是常量a
和函数myFunc
的范围不同。实际上,最后一个是全局函数,因为条件语句不会像let和const那样在其中创建函数的块作用域(我想是出于遗留原因)。
我想知道Safari在这种情况下是否正确,因为我们正在混合使用不同范围的东西。
是否有一些官方资源可以解释这种情况?我在caniuse网站和mdn网站中都没有提及此行为
解决方法
多年以来,规范中并未定义块中的函数声明,但是不同的javascript引擎允许使用它们。
由于此语法未在规范中定义,并且被javascript引擎允许,因此不同的引擎会执行不同的操作。一些人将其视为语法错误,其他人则将其作为函数表达式在块作用域中处理。一些引擎将函数声明视为在块范围内,就像同一范围中的多个提升声明一样。
从ES2015开始,函数声明是规范的一部分,有两种处理方法:
- 标准网络语义
- 旧版网络语义
标准语义学
使用标准语义,函数声明将转换为函数表达式,并使用let
关键字进行声明,并被提升到块的顶部。标准语义在严格模式下有效。
因此,在严格模式下,JavaScript引擎会将您的代码视为这样编写:
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
myFunc();
}
旧版网络语义
在浏览器的非严格模式下,将应用旧版Web语义。如果将块范围内的函数声明未视为语法错误,则所有主要的JavaScript引擎都会以相同的方式处理three scenarios
。这三种情况是:
- 在单个块中声明和引用函数
- 在单个块中声明了一个函数,并且可能在其中使用该函数,但该函数也被不包含在同一块中的内部函数定义引用。
- 在单个块中声明并可能使用了函数,但也可以在其中引用 后续区块。
除了在块作用域中定义的函数的let
变量外,在包含函数作用域或全局范围中还有一个用var
定义的变量。 var
的分配不会被提升到块的顶部,而是在代码中到达函数声明时完成的。
您的非严格模式下的代码被javascript引擎视为:
var varMyFunc;
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
varMyFunc = myFunc; // at the place of function declaration
myFunc();
}
您不应编写依赖于传统Web语义的代码。相反,请使用严格模式以确保您的代码依赖标准规则来处理块作用域中的函数声明。综上所述,如果您有非严格模式下的遗留代码依赖于遗留Web语义,则可以期望它可以跨浏览器工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。