8

I want to write a test suite to ensure some given functions are using strict mode. There are many of them, and manually inspecting them seems like a chore.

An answer in a similar question uses a regex on the function's definition to check. However, I believe this will misdetect situations where the function being tested is inside a function with "use strict" or a file-level "use strict" declaration. The answer says that "use strict" is prepended, but in my environment (Mozilla Rhino), this is not the case:

$ cat strict_sub.js
"use strict";
var strict_function = function() {
    not_a_real_global = "foo";
};

print(strict_function);
$ rhino strict_sub.js 

function () {
    not_a_real_global = "foo";
}

I feel like the answer is "no", but is there no way to introspect a function to see if it was parsed and found to be strict mode?

Update: One method suggest by @Amy was to parse the function's source to figure it out. This works if the function has a use-strict declaration (although it's tedious), but not if it the strict-mode is propagation from, say, Program-level; in that case, we have to walk up the AST to the Program level and check that for use strict. To make this robust, we'd have to implement all the rules for use strict-propagation, which the interpreter already has somewhere.

(Tested in SpiderMonkey:

function f() {
  "use strict";
}
var fast1 = Reflect.parse(f.toString());

var first_line = fast1.body[0].body.body[0].expression;

print(first_line.type === 'Literal' && first_line.value === 'use strict'); //true

)

Community
  • 1
  • 1
nfirvine
  • 1,479
  • 12
  • 23
  • I usualy use this: var isStrict = (function() { return !this; })(); console.log(isStrict); – Shakawkaw Dec 02 '15 at 19:48
  • @Shakawkaw: but that needs be run inside the function to be tested. I need to test it externally. – nfirvine Dec 02 '15 at 19:49
  • 1
    *"is there no way to introspect a function to see if it was parsed and found to be strict mode"* No. – Felix Kling Dec 02 '15 at 19:51
  • Not without parsing it yourself (such as with the Spidermonkey Parser API) and checking the resulting AST, no. –  Dec 02 '15 at 19:55
  • @Amy: I tried parsing with Spidermonkey, but it really only tells me that (for example) there is a string literal there. If there's a file-level strict, I would have to check for that myself as well. – nfirvine Dec 04 '15 at 01:24
  • Right. You would have to parse the whole file. –  Dec 04 '15 at 02:26

1 Answers1

5

Strict mode functions do have a "poisoned" .caller and .arguments properties (also ES5, extra), so you can test that:

function isStrict(fn) {
    if (typeof fn != "function")
        throw new TypeError("expected function");
    try {
        fn.caller; // expected to throw
        return false;
    } catch(e) {
        return true;
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Spec source would be useful. – Ben Aston Dec 02 '15 at 20:01
  • Oh dang, I confused [Function `.caller`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller) with the **`arguments` object** which does have these poisoned properties (@BenAston: [ES5](http://es5.github.io/#x10.6), [ES6](http://www.ecma-international.org/ecma-262/6.0/#sec-arguments-exotic-objects)) – Bergi Dec 02 '15 at 20:06
  • @BenAston: Oh, I just stumbled across it: strict mode function objects actually do have poisoned properties as well – Bergi Dec 10 '15 at 16:36
  • I'm just not sure whether this still works with ES6, where these poisoned properties seem to be inherited from `Function.prototype`, so that even sloppy mode functions may have them if an environment does not create non-standard own properties for them. – Bergi Dec 10 '15 at 16:42
  • Not sure I'm totally following, but I implemented your function and made some tests. In Spidermonkey, works well. In Rhino, seems like [function.caller is not implemented](http://stackoverflow.com/questions/8986828/is-it-possible-to-add-function-caller-support-to-rhino) :( Even though your answer doesn't work in Rhino, I'd argue it's Rhino that's broken. – nfirvine Dec 10 '15 at 19:05
  • @nfirvine: This function doesn't rely on the `.caller` support for functions. It relies on the ES5 spec requiring that strict mode functions *don't implement* it, and even more, that it must throw. Did you test in Rhino? Does Rhino follow ES5 or ES6? – Bergi Dec 11 '15 at 03:47