在Javascript中,如何检查一个函数是否处于严格模式而不改变这个函数本身?

8

我想编写一个测试套件来确保一些给定的函数使用了严格模式。这些函数有很多,手动检查似乎很繁琐。

一个类似问题的答案使用函数定义的正则表达式来检查。但是,我认为这种方法会误判测试的函数在一个带有"use strict"的函数或文件级别"use strict"声明的情况下。答案说"use strict"被预先添加,但在我的环境(Mozilla Rhino)中并非如此:

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

我觉得答案是否定的,但有没有办法内省一个函数以查看它是否已被解析并发现为严格模式?

更新:@Amy建议的一种方法是解析函数的源代码来找出它。如果该函数有使用严格声明(虽然这很繁琐),但如果它是从某个级别(例如程序级别)传播的严格模式,则无法找到。在这种情况下,我们必须遍历AST到程序级别并检查那里是否有use strict。为了使其更加健壮,我们必须实现所有use strict传播规则,而解释器已经在某个地方实现了这些规则。

(在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

)


通常我会使用这个:var isStrict = (function() { return !this; })(); console.log(isStrict); - Shakawkaw
@Shakawkaw:但那需要在被测试的函数内运行。我需要在外部进行测试。 - nfirvine
1
没有办法内省一个函数,来查看它是否被解析并发现是严格模式。不行。 - Felix Kling
不可以不解析它(例如使用Spidermonkey Parser API)并检查生成的AST。 - user47589
@Amy:我尝试使用Spidermonkey解析,但它只告诉我那里有一个字符串字面量(例如)。如果有文件级别的严格模式,我也必须自己检查。 - nfirvine
没错,你需要解析整个文件。 - user47589
1个回答

5

严格模式下的函数确实存在“被污染”.caller.arguments属性(同样适用于ES5额外规范),所以您可以进行测试:

function isStrict(fn) {
    if (typeof fn != "function")
        throw new TypeError("expected function");
    try {
        fn.caller; // expected to throw
        return false;
    } catch(e) {
        return true;
    }
}

规格源将会很有用。 - Ben Aston
哦,我混淆了函数.caller和**arguments对象**,后者确实有这些有毒属性(@BenAston: ES5, ES6)。 - Bergi
@BenAston:哦,我刚刚偶然发现了这个问题:严格模式函数对象实际上也有毒化属性。 - Bergi
我不确定这是否仍然适用于ES6,在那里这些被污染的属性似乎是从Function.prototype继承的,因此即使松散模式的函数在环境中没有为它们创建非标准的自有属性,它们也可能具有这些属性。 - Bergi
不确定我是否完全理解,但我实现了您的函数并进行了一些测试。在Spidermonkey中,运行良好。在Rhino中,似乎function.caller未实现 :( 即使您的答案在Rhino中无法工作,我认为是Rhino出了问题。 - nfirvine
@nfirvine:这个函数不依赖于函数的.caller支持。它依赖于ES5规范要求严格模式函数不实现它,甚至更多,它必须抛出异常。你在Rhino中测试过吗?Rhino遵循ES5还是ES6? - Bergi

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