我可以为特定函数禁用ECMAscript的严格模式吗?

87

我在MDC或ECMAscript规范中没有找到关于我的问题的任何信息。也许有人知道一种更“巧妙”的方法来解决这个问题。

我在我的环境中为每个JavaScript文件调用“use strict”。所有我的文件都以此开始。

(function(win, doc, undef) {
    "use strict";

    // code & functions
}(window, window.document));

现在,我有一个自定义函数来处理错误。该函数使用.caller属性来提供一个上下文调用堆栈。看起来像这样:

var chain = (function() {
    var _parent = _error,
        _ret = '';

    while( _parent.caller ) {
        _ret += ' -> ' + _parent.caller.name;
        _parent = _parent.caller;
    }

    return _ret;
}());

然而,在严格模式下,.caller是一个不可删除的属性,当调用时会抛出错误。因此我的问题是,有人知道一种“逐函数”禁用严格模式的方法吗?

"use strict";被所有函数继承,只要在调用后它被调用。现在我们可以通过在特定函数顶部调用"use strict";来仅在这些函数中使用严格模式,但是否有一种实现相反效果的方法呢?


你可以使用全局 eval 来绕过严格模式。 - Raynos
1
如果其他人需要知道这是关于什么的:use strict是什么 - mplungjan
我几乎希望这样的东西不存在。 "use strict" 的想法是一种向后兼容的选择策略。我不确定我是否喜欢前后兼容的想法,即我们允许代码选择加入,然后再允许代码的子部分选择退出。 - davin
你可以在这里看到解决方案:**>>只需更改.babelrc** - hisland
3个回答

104

不,你不能针对每个函数禁用严格模式。

重要的是要理解严格模式是按照词法作用域工作的;这意味着它会影响函数声明,而不是执行。在严格模式下声明的任何函数本身都会成为严格函数。但并非在严格代码内部调用的每个函数都必须是严格的:

(function(sloppy) {
  "use strict";

   function strict() {
     // this function is strict, as it is _declared_ within strict code
   }

   strict();
   sloppy();

})(sloppy);

function sloppy(){
  // this function is not strict as it is _declared outside_ of strict code
}

请注意,我们可以在严格模式之外定义函数,然后将其传递给严格模式的函数。
您可以在示例中执行类似操作 - 使用具有“松散”函数的对象,然后将该对象立即传递给严格调用的函数。当然,如果“松散”函数需要引用主包装函数内的变量,则无法使用此方法。
此外,请注意间接eval - 其他人建议的方法 - 在这里并不真正有用。它所做的只是在全局上下文中执行代码。如果您尝试调用在本地定义的函数,则间接eval甚至找不到它:
(function(){
  "use strict";

  function whichDoesSomethingNaughty(){ /* ... */ }

  // ReferenceError as function is not globally accessible
  // and indirect eval obviously tries to "find" it in global scope
  (1,eval)('whichDoesSomethingNaughty')();

})();

关于全局eval的困惑可能来自于这样一个事实,即全局eval可以用于在严格模式下从中获取对全局对象的访问(这不再是通过this简单地访问):

(function(){
  "use strict";

  this; // undefined
  (1,eval)('this'); // global object
})();

但回到问题本身...

你可以通过Function构造函数来创建一个新的函数,这种方法不会继承严格模式,但是这将依赖于(非标准)函数反编译,并且你将失去引用外部变量的能力

(function(){
  "use strict";

  function strict(){ /* ... */ }

  // compile new function from the string representation of another one
  var sneaky = Function('return (' + strict + ')()');

  sneaky();
})();

注意,从我所知道的情况来看,FF4+似乎与规范不一致,并错误地将通过Function创建的函数标记为严格模式。这在其他支持严格模式的实现(如Chrome 12+、IE10、WebKit)中不会发生。

如何向 sneaky 函数传递参数? - Szymon Toda
谢谢,我在Jasmine单元测试中遇到了一个棘手的问题,需要修改被测试类使用的全局变量,但我无法做到。这个技巧真是太棒了! - Juangui Jordán
@kangax,如果我正在使用严格模式,但我想动态禁用它。也就是说,我将一个函数声明为严格模式,但在某些情况下,我不希望该函数成为严格模式,并且我想将该函数更改为非严格模式。我应该怎么做? - Jeyanth

5

(来源:http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/)

(...) 严格模式不会强制执行在严格模式下调用的非严格函数(无论是因为它们作为参数传递还是使用 callapply 调用)。

因此,如果您在没有启用严格模式的不同文件中设置错误方法,然后将其作为参数传递,如下所示:

var test = function(fn) {
  'use strict';
  fn();
}

var deleteNonConfigurable = function () {
  var obj = {};
  Object.defineProperty(obj, "name", {
    configurable: false
  });
  delete obj.name; //will throw TypeError in Strict Mode
}

test(deleteNonConfigurable); //no error (Strict Mode not enforced)

...它应该能正常工作。


在Firefox 4中似乎对我无效。我已经完全删除了文件和方法中的严格指令,以及错误处理方法。但我仍然会收到严格模式的错误。 - jAndy

4
一个替代方案就是直接这样做。
var stack;
if (console && console.trace) {
     stack = console.trace();
} else {
    try {
        var fail = 1 / 0;
    } catch (e) {
        if (e.stack) {
            stack = e.stack;
        } else if (e.stacktrace) {
            stack = e.stacktrace;
        }
    }
}
// have fun implementing normalize.
return normalize(stack);

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