我正在开始一个新的JavaScript应用程序,并希望使用严格模式。但是,我们仍然需要支持一些不支持严格模式的旧浏览器(IE8,9)。我的一些同事担心严格模式带来的运行时语义变化 - 他们担心严格的函数在旧浏览器上以松散模式运行时的行为会有所不同。
是否有一些额外的限制我可以添加以确保函数在松弛模式下具有与严格模式相同的运行时语义?具体来说,我想要一组我可以检查的规则自动的,类似于lint的工具。我的第一个想法是阻止人们使用eval
或arguments
。那就够了吗?
coffeescript中的编码是否有助于实现这一目标?
例如,请考虑以下函数:
(function(){
'use strict';
function foo(bar) {
arguments[0] = 'You are in lax mode';
alert(bar);
}
foo('You are in strict mode');
})();
此功能在严格模式下正常运行,但在松弛模式下具有不同的行为。我正在寻找一套规则,以确保人们不会意外地做到这一点。
答案 0 :(得分:3)
所有严格模式功能都汇总在ECMAScript规范的Annex C中。在大多数情况下,当您尝试使用不允许的功能(新保留字,八进制文字和转义序列,对象文字中相同属性的多个定义等)时,严格模式将抛出错误。我理解你的问题是关于不会引起任何错误的案例,所以这里是:
严格模式函数的参数对象不会使用其函数的相应形式参数绑定动态共享其数组索引属性值。 (10.6)。
对于严格模式函数,如果创建了一个arguments对象,则本地标识符参数与arguments对象的绑定是不可变的,因此可能不是赋值表达式的目标。 (10.5)。
这会导致您所拥有的示例中出现的问题。如果您完全不允许使用arguments
,那么这里不会有任何问题。我个人认为不允许使用arguments
过于激进,但那是你的要求。
- 严格模式评估代码无法在调用者的变量环境中将变量或函数实例化为eval。而是创建一个新的变量环境,该环境用于eval代码的声明绑定实例化(10.4.2)。
你也不允许eval
,所以你也很好。
如果在严格模式代码中评估
this
,则this
值不会强制转换为对象。this
值null
或undefined
未转换为全局对象,并且原始值不会转换为包装器对象。通过函数调用传递的this
值(包括使用Function.prototype.apply
和Function.prototype.call
进行的调用)不会强制将此值传递给对象(10.4.3,11.1.1,15.3。 4.3,15.3.4.4)。
这意味着两件事:
this
在未定义的情况下不会被强制转换为全局对象,因此:
//"use strict";
function foo() {
console.log(this);
}
foo();
// logs undefined in strict mode, and window in classic mode
我不认为这个可以用静态分析来捕获。它可能会在严格模式下导致错误,具体取决于您对this
的处理方式。例如,函数this.foo = 'bar'
内部将在经典模式下创建一个全局变量,但在经典模式下引发TypeError。但是typeof this
不会抛出任何错误,只会产生不同的结果。
this
在设置为原始值时不会被强制转换为包装器对象。例如:
//"use strict";
function valtype() { return typeof this }
console.log(valtype.call("foo"));
// logs "string" in strict mode and "object" in classic mode
这个听起来不是什么大问题,但可能会引起问题。我也认为静态分析无法检测到这一点。
底线:施加限制并为此创建lint工具可能不是最佳解决方案。它甚至可能是不可能的。为什么不改为创建一组单元测试呢?
答案 1 :(得分:1)
回答问题的第二部分:
coffeescript中的编码是否有助于实现这一目标?
是和否。您提供的示例与语义相关(因为大多数严格模式都是如此)。 Coffeescript改变了语法,但语义保持不变。
Coffeescript issue #1547讨论了coffeescript 支持的语法检查的一些功能。
另外,在CS隐含解决的问题中没有讨论过一些案例:
window
with
块:它根本无法形成这样的块 arguments
的问题是largely mitigated with splats Coffeescript有点帮助,但这不是治愈方法。你仍然可以用脚射击自己,但它确实试图让你更明确地这样做。
我应该指出,Coffeescript拯救你的大多数东西都是JSHint和JSLint试图解决的问题。您可能只想使用其中一种而不是移动到另一种语言。
答案 2 :(得分:-1)
我认为您最好的选择是在严格模式的浏览器上测试您的代码。这是提供真实结果的唯一途径。