【问题标题】:How is JavaScript's strict mode implementedJavaScript 的严格模式是如何实现的
【发布时间】:2012-07-05 22:03:00
【问题描述】:

更新:

也许函数调用的方式是罪魁祸首,所以这里是它:

2 JS 文件
  Main.js:自调用(非严格)函数,为“(on)load”事件添加事件侦听器。
回调调用加载器函数,该函数解析 location.pathname,调用 init 函数,分离/删除“(on)load”侦听器并返回 null(显式)。

PageSpecific.js:包含 _init 函数,在正文中添加了几个事件侦听器。
这些侦听器之一的回调(也从闭包返回)调用使用 argument.callee 作为递归引用的严格函数。
返回事件处理程序的闭包可能 - 取决于浏览器 - 或者可能不绑定和取消绑定其他事件,但我认为这无关紧要,因为这是模仿 IE 中的 onchange 事件

我希望这是相当清楚的,所以它:
anon。 F => eventlistener
            => 处理程序(已命名但在匿名 F 中声明)=> pageloader =>
                 init => eventListener
                  闭包返回的绑定函数
                  => 调用严格函数

顺便说一句:Here's a trimmed down version of the _init function 被称为,我实际上正在使用。更具体地说:将事件侦听器和 - 处理程序绑定在一起的闭包。这是我的另一个冗长的问题,似乎没有人知道答案... hint ;-)


我正在调试一些相当大(且复杂)的 JavaScript。在这样做时,我注意到我有一个函数,使用严格模式可以正常工作,但如果我没记错的话,应该抛出错误。由于脚本相当庞大和复杂(事件委托、堆叠闭包等),这里有一个简单的例子:

function withCalleeRecursion(foo)
{
    'use strict';//strict throws typeError on arguments.callee
    foo = foo.replace(/(a|b)+/gi, function (p1,p2)
    {
        if (p1.match(/(a|b){2,}/i))
        {
            return p1.replace(/(a|b)/gi,arguments.callee);//no errors
        }
        return (p2.match(/a/i) ? 'X':'Y');
    });
    return foo;
}

(function()
{//not strict
    alert(withCalleeRecursion('Abba makes me barf'));
})();

在我的实际脚本中,这非常好。但是,当我将其粘贴到 Firebug 和 chrome 控制台中时,会引发错误。我试过这段代码here,所以IE也应该抛出错误,但是当我在IE的调试器中运行代码时,它工作得很好。据我所知,更改文档类型(尝试过 html5 和 html4)没有区别。

我认为(大多数)浏览器对 'use strict'; 指令的要求并不像它的名字所暗示的那样严格吗?当解析脚本时检测到可能的错误时,浏览器似乎选择忽略它。这是真的吗?


同时,出于谨慎起见,我对功能做了些微改动。由于我在这里看到很多人想知道如何在严格模式下获得 callee 引用,因此我也将其粘贴在这里:

function withCalleeRecursion(foo)
{
    'use strict';
    foo = foo.replace(/(a|b)+/gi, function abR(p1,p2)
    {
        if (p1.match(/(a|b){2,}/i))
        {
            return p1.replace(/(a|b)/gi,abR);
        }
        return (p2.match(/a/i) ? 'X':'Y');
    });
    return foo;
}

为回调命名,仅此而已。

【问题讨论】:

  • 来自MSDN - “Internet Explorer 10 之前的 Internet Explorer 版本不支持严格模式。”您认为arguments.callee 应该在严格模式下抛出错误是正确的。
  • 严格模式实现背后的想法是,"use strict"; 在不支持的浏览器中的声明将完全无害。
  • 很公平,我也这么认为......不过,该脚本也适用于 FF 和 chrome。两个最新版本 - 他们确实支持strict mode
  • @EliasVanOotegem - 当我运行 your code in JSFiddle 时,Chrome 会抛出预期的 TypeError。
  • 我也设置了一个小提琴,我也得到了错误。我在那里尝试了所有的文档类型,每次我得到错误。也许它与调用堆栈有关?我将更新问题以给出函数调用方式的示意图

标签: javascript recursion strict


【解决方案1】:

这可能是因为浏览器控制台使用了eval(),这改变了一些事情。尽管将"use strict"; 放在传递给eval() 的代码字符串的开头可以按预期工作,但控制台实现可能会将代码添加到您在控制台中键入的字符串之前,这意味着"use strict"; 不再是执行的第一条语句因此被忽略。

在以下文章中有对此的参考和建议的解决方法:

http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/

建议的解决方法是将控制台中的代码包装在一个立即执行的函数中:

(function() {
    "use strict";
    nonExistentVariable = 1; // Error is now thrown
})();

【讨论】:

  • 我已经做到了,但我想我的问题并不清楚:错误是在控制台(FF和chrome)中抛出的,但不是在使用该功能的页面上!在我的实际脚本中调用该函数时,我可以alert()console.log() 和使用arguments.callee,就好像'use strict'; 不存在一样。上面的代码在任何地方都有效(我的意思是:它不是),但不是在我的脚本本身中
  • @EliasVanOotegem:啊,抱歉,我想我没有正确阅读问题。
【解决方案2】:

也许this的文章可以帮助你了解更多。无论如何,解决方案是您提到的那个,错误是因为访问 arguments.caller 和 arguments.callee 在严格模式下抛出异常。因此,您要引用的任何匿名函数都需要命名。

【讨论】:

  • 我之前已经读过那篇文章了。我的问题不是为什么会抛出错误,而是为什么没有抛出。不在 IE 中,不在 FF 中,不在 chrome 中...
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2012-01-28
  • 2022-12-22
  • 2015-03-02
相关资源
最近更新 更多