2

我正在启动一个新的 javascript 应用程序并想使用严格模式。但是,我们仍然需要支持一些不支持严格模式的旧浏览器(IE8,9)。我的一些同事担心严格模式带来的运行时语义变化——他们担心在旧浏览器上以宽松模式运行时严格函数的行为会有所不同。

我可以添加一组额外的限制来确保函数在宽松模式下与严格模式下具有相同的运行时语义吗?具体来说,我想要一组规则,我可以使用自动化的类似 lint 的工具进行检查。我的第一个想法是防止人们使用evalor arguments。这样就够了吗?

CoffeeScript 中的编码有助于实现这一目标吗?


例如,考虑以下函数:

(function(){
 'use strict';

 function foo(bar) {
    arguments[0] = 'You are in lax mode';
    alert(bar);
 }
 foo('You are in strict mode');
 })();

此函数在严格模式下正常运行,但在宽松模式下具有不同的行为。我正在寻找一套规则,以确保人们不会意外地这样做。

4

3 回答 3

3

所有严格模式的特性都在ECMAScript 规范的附录 C中进行了总结。在大多数情况下,当您尝试使用不允许的功能(新的保留字、八进制文字和转义序列、对象文字中同一属性的多个定义等)时,严格模式会引发错误。我了解您的问题是关于不会引发任何错误的情况,因此它们是:

  • 严格模式函数的参数对象不会与其函数的相应形式参数绑定动态共享其数组索引属性值。(10.6)。

  • 对于严格模式函数,如果创建参数对象,则本地标识符参数到参数对象的绑定是不可变的,因此可能不是赋值表达式的目标。(10.5)。

这会导致您在示例中看到的问题。如果您完全禁止使用arguments,那么这里就不会有任何问题。我个人认为禁止使用arguments太激进了,但这是你的决定。

  • 严格模式 eval 代码无法在调用者的变量环境中实例化变量或函数以进行 eval。相反,会创建一个新的变量环境,并且该环境用于 eval 代码 (10.4.2) 的声明绑定实例化。

你也不允许eval,所以你在这里也很好。

如果this在严格模式代码中进行评估,则该this值不会强制转换为对象。or的this值不转换为全局对象,原始值不转换为包装对象。通过函数调用传递的值(包括使用and进行的调用)不会将传递的值强制传递给对象(10.4.3、11.1.1、15.3.4.3、15.3.4.4)。nullundefinedthisFunction.prototype.applyFunction.prototype.call

这意味着两件事:

  1. 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不会抛出任何错误,只会产生不同的结果。

  2. this当它被设置为原始值时,不会被强制转换为包装器对象。例如:

    //"use strict";
    function valtype() { return typeof this }
    console.log(valtype.call("foo"));
    // logs "string" in strict mode and "object" in classic mode
    

    这听起来没什么大不了的,但可能会引起问题。我也认为静态分析无法检测到这一点。

底线:施加限制并为此创建一个 lint 工具可能不是最好的解决方案。这甚至可能是不可能的。你为什么不创建一组单元测试呢?

于 2013-06-25T17:21:16.310 回答
1

要回答您问题的第二部分:

CoffeeScript 中的编码有助于实现这一目标吗?

是和不是。您给出的示例与语义有关(就像大多数严格模式一样)。Coffeescript 改变了语法,但语义保持不变。

Coffeescript 问题 #1547讨论了 coffeescript 支持的一些语法检查功能。

此外,CS 隐含地解决了该问题中未讨论的某些情况:

  • 意外全局变量:全局变量只能通过将它们附加到window
  • with块:它根本无法形成这样的
  • splats 的问题arguments 很大程度上得到缓解

Coffeescript 有点帮助,但它不是治愈方法。你仍然可以用它来打自己的脚,但它确实试图迫使你更明确地这样做。

我应该指出,Coffeescript 为您节省的大部分东西都是 JSHint 和 JSLint 试图解决的相同问题。您可能只想使用其中一种语言,而不是转向另一种语言。

于 2013-06-30T23:51:33.723 回答
-1

我认为你最好的选择是在严格模式的浏览器上测试你的代码。这是提供真实结果的唯一方法。

于 2013-06-28T23:56:02.447 回答