在 javascript 中重新分配函数声明
Re-assigning a function declaration in javascript
现在我正在调试自 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())" 作为函数的第一条语句,它会在第一次调用时打印初始函数。所有进一步的调用都会打印 nullMethod。
有人可以解释可能是什么原因吗? IE11 工作正常。 Chrome 与 Firefox 46 有同样的问题。自引入此行为以来,我只是没有找到旧的 Chrome 版本来验证。覆盖以这种方式声明的函数是否有效?
jsbin.com 在函数重新分配行上发出警告:
Line 6: 'f' is a function.
本例中的方法 f
是一个 Java 静态初始化程序。 运行 它不止一次会在模拟的 Java 中引起问题,它预计这只能 运行 一次,当 class 首次被引用或加载时(忽略 class加载程序问题,因为 GWT 不模拟 class加载程序)。
然而,足够旧的 GWT 副本将代码块包裹在 try
/catch
块中(iirc 这与 IE6 问题有关),并且在当时,JS 范围规则有它们周围的一些歧义使得这段代码始终如一地工作,因为所有浏览器都支持它。这被称为 "sloppy mode self-defining function"。
作为 ES2015 的一部分,已经决定 try 块与外部 "function-hosted" 块具有不同的范围(即,当您将某些内容声明为 function foo() {...}
时,它存在于高级范围)。在 https://github.com/tc39/ecma262/issues/162.
上看到大量关于此的讨论
此更改意味着一些以前正常的程序不再正常工作 - 有一段时间,这包括 Google Inbox 以及其他程序。
更新到较新版本的 GWT,或使用不再包装旧 GWT 中每个顶级 JS 块的自定义 Linker
应该可以解决此问题。如果您仍然必须支持任何需要这种行为的古老浏览器(有足够的代码考古学,我相信我们可以找出 GWT 最初这样做的原因,但我还没有这样做),您将不得不找到一个在古老的浏览器和前沿浏览器中都有效的妥协。
现在我正在调试自 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())" 作为函数的第一条语句,它会在第一次调用时打印初始函数。所有进一步的调用都会打印 nullMethod。
有人可以解释可能是什么原因吗? IE11 工作正常。 Chrome 与 Firefox 46 有同样的问题。自引入此行为以来,我只是没有找到旧的 Chrome 版本来验证。覆盖以这种方式声明的函数是否有效?
jsbin.com 在函数重新分配行上发出警告:
Line 6: 'f' is a function.
本例中的方法 f
是一个 Java 静态初始化程序。 运行 它不止一次会在模拟的 Java 中引起问题,它预计这只能 运行 一次,当 class 首次被引用或加载时(忽略 class加载程序问题,因为 GWT 不模拟 class加载程序)。
然而,足够旧的 GWT 副本将代码块包裹在 try
/catch
块中(iirc 这与 IE6 问题有关),并且在当时,JS 范围规则有它们周围的一些歧义使得这段代码始终如一地工作,因为所有浏览器都支持它。这被称为 "sloppy mode self-defining function"。
作为 ES2015 的一部分,已经决定 try 块与外部 "function-hosted" 块具有不同的范围(即,当您将某些内容声明为 function foo() {...}
时,它存在于高级范围)。在 https://github.com/tc39/ecma262/issues/162.
此更改意味着一些以前正常的程序不再正常工作 - 有一段时间,这包括 Google Inbox 以及其他程序。
更新到较新版本的 GWT,或使用不再包装旧 GWT 中每个顶级 JS 块的自定义 Linker
应该可以解决此问题。如果您仍然必须支持任何需要这种行为的古老浏览器(有足够的代码考古学,我相信我们可以找出 GWT 最初这样做的原因,但我还没有这样做),您将不得不找到一个在古老的浏览器和前沿浏览器中都有效的妥协。