现在我正在调试自Firefox 46以来我的GWT(版本2.5.1)应用程序中发生的一些奇怪错误.GWT生成的javascript代码包含此模式的多个实例:
function nullMethod() {
}
var v;
function f() {
f = nullMethod;
v = { name : 'Joe' };
console.log("called");
}
// this is called from multiple places
console.log((f(), v).name);
console.log((f(), v).name);
console.log((f(), v).name);
似乎这以某种方式实现了单例模式。但由于某种原因,这并不能防止再次调用初始声明的方法。字符串'called'多次打印到控制台。
但如果我尝试通过一点测试重现这一切,一切都按预期工作。上面的观察是通过向生成的代码添加控制台输出(> 5MB)来完成的。
现在真的很奇怪。如果我添加“console.log(f.toString())”作为函数的第一个语句,它会在第一次调用时打印intial函数。所有进一步的调用都会打印nullMethod。
有人可以解释可能的原因吗? IE11工作正常。 Chrome与Firefox 46具有相同的问题。我从未找到旧的Chrome版本进行验证,因为引入了此行为。覆盖以这种方式声明的函数是否有效?
jsbin.com在功能重新分配行上发出警告:
Line 6: 'f' is a function.
答案 0 :(得分:1)
在这种情况下,方法f
是一个Java静态初始化程序。多次运行会导致模拟Java出现问题,这种问题在首次引用或加载类时只能运行一次(忽略类加载器问题,因为GWT不会模拟类加载器)。
但是,GWT的足够旧的副本会在try
/ catch
块中包含代码块(这与IE6问题有关),当时JS范围规则有些含糊不清因为所有浏览器都支持这个,所以这些代码一致地工作。这被称为“草率模式自定义函数”。
作为ES2015的一部分,已经确定try块与外部“函数托管”的范围不同(即当您将某些内容声明为function foo() {...}
时,它存在于高级别中范围)。请参阅https://github.com/tc39/ecma262/issues/162上的大量讨论。
这一变化意味着一些以前理智的程序不再正常工作 - 有一段时间,这包括谷歌收件箱以及其他人。
更新到更新版本的GWT,或者使用不再包含旧GWT中每个顶级JS块的自定义Linker
应解决此问题。如果你仍然必须支持任何需要这种行为的古老浏览器(有足够的代码考古,我相信我们可以找出为什么GWT最初做了它,但我还没有这样做),你将不得不找到一个妥协在古代和前沿的浏览器中都有效。