如何确保ES3程序可以在ES5引擎中运行?

6

因此,ECMAScript 5对ECMAScript 3引入了一些不兼容性。


示例

许多 文章 已经说明在 ES5严格模式中可以使用this === null || this === undefined

"use strict";
(function () {
    alert(this); // null
}).call(null);

但是,标准实际上建议ES5引擎也允许在非严格模式下使用:

15.3.4.3 ... thisArg值作为this值传递而不进行修改。这是从第3版变化过来的,第3版中,undefinednull的thisArg会被替换为全局对象,并且ToObject会应用于所有其他值,该结果将作为this值传递。

目前,IE9是唯一实际按照ES5实现的浏览器,结果发现这可能会破坏当前脚本。太好了。


ES5规范的Annix E列出了许多其他不兼容性。

那么,确保我们经过充分测试的ES3脚本继续无故障运行的最佳方法是什么?某种自动化测试套件?还是我们必须手动测试所有内容?

2个回答

6
值得注意的是,提问者对ES5 15.3.4.3的解释是错误的。在ES5中,对于任何非严格函数的调用,应该与ES3中的调用一样。全局对象仍然会被传递到使用null或undefined作为this值的任何非严格函数中。
分析的遗漏部分是10.4.3“进入函数代码”:
以下是在函数对象F、调用者提供的thisArg和调用者提供的argumentsList中包含的函数代码的执行上下文进入时执行的步骤: 1.如果函数代码是严格代码,请将ThisBinding设置为thisArg。 2.否则,如果thisArg为null或undefined,请将ThisBinding设置为全局对象。 3.......
ES3规定调用者负责将全局对象替换为null或undefined的this值。ES5规定被调用方有此责任(如果它不是严格模式函数)。对于非严格代码,这不是一个可观察的差异。规范更改只有在被调用方是严格函数时才会有所不同。

笔误:值为“未定义” - Axel Rauschmayer
@AxelRauschmayer - ES5必须这样工作,因为调用者不一定知道被调用方是否处于严格模式。因此,从调用中传递thisArg并让被调用方进行排序是有意义的。 :-) - RobG

4

自动化测试套件肯定是一个好主意。

由于越来越多的实现现在实现了ES5,运行新版浏览器中的脚本/库/应用程序的测试套件是确保兼容性的好方法。

我有一个 ES5兼容性表,列出了一些更受欢迎的实现的支持级别。它不是详尽无遗的,但它显示了整体方向——最新的IE、WebKit、Chrome和Firefox都具有相当好的ES5支持。对于完整的一致性测试,您可以随时运行官方ES5测试套件(我在这里 这里为方便起见在线提供)。

如果没有测试套件(这真的应该存在,因为它非常有用),您可以在较新的(符合ES5标准的)实现之一中运行脚本/库/应用程序,看看哪些有效,哪些失败。

Consulting 附录E 是另一种方法。请注意,尽管列表看起来很长,但实际情况并不像看起来那么糟糕。ES5 的目标之一是使从 ES3 的过渡相对轻松,将更激进的变化移入选择性严格模式的领域。
许多兼容性更改可能不会被注意到。例如,在15.1.1中进行的更改,全局的undefinedNaNInfinity现在是只读的。考虑到理智的应用程序不会重新分配这些全局属性——除了错误地——这个变化更像是一个愉快的“错误捕捉器”,而不是“应用程序破坏者”。

我是一个有用的助手,可以翻译文本。

另一个可能是无辜的变化出现在15.10.2.12中,其中空格字符类 (\s) 现在也匹配 <BOM> (U+FEFF) 字符。考虑到当前实现中的所有偏差 (甚至是关于 ES3),这种变化很可能在大多数应用程序中不会被注意到。

然而,还有更危险的变化,比如 parseInt 中的变化,它不再将以0开头的字符串视为八进制值。 parseInt('010') 不应该再产生 8 了 (尽管一些实现选择故意违反那种行为)。而且,依赖于没有第二个“基数”参数的parseInt从来都不是一个好习惯。因此,如果你的应用程序总是指定基数,就没有什么可担心的了。

所以,请参考附录 E,在更新的实现中测试你的脚本 (最好是多个实现),并遵循最佳实践。这是确保兼容性的好方法。


你的测试套件真的很不错。然而,恐怕它对我的特定情况没有帮助。基本上,我的公司需要确保我们的旧脚本不会在客户的安装中引起任何问题。我们谈论的是数百个脚本,手动检查每一个功能的每一个细节看起来像是一件非常痛苦的事情。(“单元测试?那是什么?”)目前,恐怕我们只能等待错误报告。 - user123444555621
通过JSLint运行脚本怎么样?一步一步地,逐个检查。JSLint可能无法涵盖所有兼容性敏感的更改,但它肯定会让你接近目标。它会警告没有基数的parseInt,以及属性名称作为关键字(例如({ if: 1 }))等问题。 - kangax
不幸的是,JSLint会报告成千上万个错误,并且偶尔会拒绝继续(例如在遇到void时),即使脚本在ES3中运行良好。事实上,我过去曾对JSLint进行了一些修改,现在正在考虑添加一些ES5内容。然而,一些不兼容性(7.8.5/1、10.4.2、10.6/2、15.3.4.3、15.3.4.4、15.10.2.12)在解析时很难找到。 - user123444555621
我也在想同样的事情——相当多的ES5更改无法通过静态(词法)分析捕获。因此,编写全面的兼容性lint工具将是具有挑战性的(如果可能的话)。说到10.4.2——间接eval——请注意,许多较新的(以及不那么新的)浏览器已经遵循ES5行为一段时间了——http://kangax.github.com/jstests/indirect_eval_call_test/,因此“更改”可能不会成为问题(ES5在这里有点规范了事实上的标准,而不是引入完全不同的行为)。 - kangax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接