问题描述
我正在使用代码块来模拟静态函数变量laC。这是基本设置:
awk -F= '/^version/{v=$2}; /^subversion/{ printf "%d.%d\n",v,$2; quit; }' file
现在使用chrome,可以正常编译,没有任何抱怨。但是在Safari中,我得到了一个
{ let bob = 5; function b() { console.log(bob++); } }
我不知道是什么原因导致这种差异,因为Chrome和Safari都处理ECMAScript 6。
解决方法
问题在于代码处于松散模式,并且您在块中声明了一个函数。块中的函数声明仅在ES2015中标准化,好吧,它们在严格模式下有意义,但在松散模式下它们……很奇怪。
在strict mode中,您的代码可以正常工作,可能与您预期的一样,也可能没有。 bob
可以访问b
...,并且bob
和b
都不能在该块之外访问,除非您进行一些操作以将其暴露在该块之外。
这是一个示例,您可以在Safari和iOS Safari上对其进行测试(我只有后者可用)。这个版本提供了一个错误:
<script>
window.onerror = e => {
document.body.insertAdjacentText("beforeend",String(e));
};
</script>
<script>
{
let bob = 5;
function b() {
document.body.insertAdjacentText("beforeend",bob++);
}
b();
}
</script>
错误是:
ReferenceError: Can't find variable: bob
此版本有效:
<script>
window.onerror = e => {
document.body.insertAdjacentText("beforeend",String(e));
};
</script>
<script>
"use strict"; // <============================
{
let bob = 5;
function b() {
document.body.insertAdjacentText("beforeend",bob++);
}
b();
}
</script>
我还在最新版本的JavaScriptCore(Apple的JavaScript引擎)v265499中复制了该行为。我安装了¹并在本地运行(将console.log
/ insertAdjacentText
更改为print
,这在大多数原始引擎可执行文件中都可用),并且在松散模式而不是严格模式下出现相同的错误
如果您希望在区块外使用b
,则最好这样做:
"use strict";
const b = (() => {
let bob = 5;
return function b() {
console.log(bob++);
};
})();
b();
这是很多的体积较大,但是...或者,使用let
:
"use strict";
let b;
{
let bob = 5;
b = function b() {
print(bob++);
};
}
b();
¹使用非常方便的jsvu
utility。
基于错误消息,Safari将您的块解释为对象文字。该语法有效,但Safari似乎对此感到窒息。
当我在自己的控制台中尝试此操作时,我可以通过在该块之后立即放置一条语句来使其工作:
{ let bob = 5; function b(){ console.log(bob++); } } console.log('foo');
但是,这似乎使函数脱离了块范围,而没有创建闭包,导致ReferenceError
声称找不到变量bob
。
我试图显式地将其包装在一个函数中,并以use strict
声明开始该函数,以防它未在strict mode中运行,因为这可能会改变行为:
function strict() {
'use strict';
{
let bob = 5;
function b() {
console.log(bob++);
}
return b;
}
}
strict()();
成功了!
TL:DR;在松散模式下,块处理很奇怪。在块内定义函数时,请使用严格模式。