0

Update:

Perhaps the way the function is called is to blame, so here's to it:

2 JS files
  Main.js: self invoking (non-strict) function that adds an event listener for the '(on)load' event.
The callback calls a loader function, that parses the location.pathname, and calls an init function, and detaches/removes the '(on)load' listener & returns null (explicitly).

  PageSpecific.js: contains the _init function, adds a couple of event listeners to the body.
One of these listeners' callback (also returned from a closure) calls the strict function that uses argument.callee as a reference for recursion.
The closure that returns the event handler may -depending on the browser- or may not bind and unbind other events, but I think that's irrelevant here, as this is to imitate an onchange event in IE <9

I hope this is reasonably clear, so its:
anon. F => eventlistener
             => handler (named but declared in anon F) => pageloader =>
                  init => eventListener
                  binding function returned by closure
                      => calls strict function

Incidentally: Here's a trimmed down version of the _init function that is called, that I'm actually using. More specifically: the closure that binds the event Listener and - handler together. Its another one of my length questions, to which nobody seems to know the answer... hint ;-)


I'm debugging some fairly large (and complex) JavaScripts. In doing this, I noticed that I have a function, using strict mode that works fine but should, if I'm not mistaken, throw errors. Since the scripts are fairly sizeable and complex (event delegation, stacked closures etc), here's a simple example:

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'));
})();

In my actual script, this works perfectly fine. When I pasted this both in Firebug and chrome console, an error is thrown, though. I've tried this code here, so IE should throw errors, too, but when I run the code in IE's debugger, it works just fine. As far as I can work out, changing the doctype (tried html5 and html4) makes no difference.

Am I right in thinking that (most) browsers aren't as strict with the 'use strict'; directive as it's name suggests? It would seem that the browsers choose to ignore it when a possible error is detected when parsing the script. Is this true?


Meanwhile, I have made a slight change to the function, just out of precaution. Since I've seen quite a few questions here of people wondering how to get the callee reference in strict mode, I'm pasting it here, too:

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;
}

Name the callback, that's all.

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • 2
    From [MSDN](http://msdn.microsoft.com/en-us/library/br230269(v=vs.94).aspx) - "Strict mode is not supported in versions of Internet Explorer earlier than Internet Explorer 10." You are correct in thinking that `arguments.callee` should throw an error in strict mode though. – James Allardice Jul 05 '12 at 13:32
  • 1
    The idea behind the implementation of strict mode is that the statement, `"use strict";` in a non-supporting browser will be perfectly harmless. – Pointy Jul 05 '12 at 13:34
  • Fair enough, I though as much... Still, the script works in FF and chrome, too. Both the latest versions - and they do support `strict mode` – Elias Van Ootegem Jul 05 '12 at 13:34
  • @EliasVanOotegem - Chrome throws the expected TypeError when I run [your code in JSFiddle](http://jsfiddle.net/jamesallardice/nPRmK/). – James Allardice Jul 05 '12 at 13:36
  • I've set up a fiddle, too and there I get the error, too. I've tried all doctypes there, and each time I get the error. Perhaps it has something to do with the call stack? I'll update the question to give a schematic representation of how the function is called – Elias Van Ootegem Jul 05 '12 at 13:42

2 Answers2

2

It's probably because browser consoles use eval(), which changes things. Although putting "use strict"; at the start of a string of code that is passed to eval() works as expected, it's possible that console implementations prepend code to the string you've typed into the console, meaning that "use strict"; is no longer the first statement executed and is therefore ignored.

There's a reference to this and a suggested workaround in the following article:

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

The suggested workaround is to wrap code in the console within a function that is immediately executed:

(function() {
    "use strict";
    nonExistentVariable = 1; // Error is now thrown
})();
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • I've done that, but I guess my question isn't clear: The errors are thrown in the console (FF and chrome), but not on the pages that use the function! When the function is called in my actual script, I can `alert()`, `console.log()`, and use `arguments.callee` as if `'use strict';` weren't there. The code above works (by that I mean: it doesn't) everywhere, but not in my script itself – Elias Van Ootegem Jul 05 '12 at 14:03
  • @EliasVanOotegem: Ah, sorry, I guess I didn't read the question properly. – Tim Down Jul 05 '12 at 14:03
0

Maybe this article can help you to understand more. Anyway the solution is the one you mention, the error is because access to arguments.caller and arguments.callee throw an exception in strict mode. Thus any anonymous functions that you want to reference will need to be named.

Chris
  • 333
  • 1
  • 7
  • I've already read that article a while back. My question was not why the error was thrown, but why **it isn't thrown**. Not in IE, not in FF, not in chrome... – Elias Van Ootegem Jul 05 '12 at 13:39