如果模块中的函数直接调用模块的其他函数(即使用模块本地的引用),则无法在外部拦截这些调用。但是,如果您更改模块,使其内部的函数以与外部代码相同的方式调用模块的函数,那么您可以拦截这些调用。
这是一个允许您想要的示例:
define([], function () {
"use strict";
var foo = function(){
return exports.bar();
};
var bar = function(){
return "original";
};
var exports = {
foo: foo,
bar: bar
};
return exports;
});
关键是foo
通过exports
访问bar
而不是直接调用它。
我在这里提出了一个可运行的示例。该spec/main.spec.js
文件包含:
expect(moduleA.foo()).toEqual("original");
spyOn(moduleA, "bar").andReturn("patched");
expect(moduleA.foo()).toEqual("patched");
您会注意到这bar
是修补的功能,但foo
受修补的影响。
此外,为了避免导出被测试代码永久污染,我有时会进行环境检查以确定模块是否在测试环境中运行,并仅在测试模式下导出测试所需的功能。这是我编写的实际代码示例:
var options = module.config();
var test = options && options.test;
[...]
// For testing only
if (test) {
exports.__test = {
$modal: $modal,
reset: _reset,
is_terminating: _is_terminating
};
}
如果 requirejs 配置配置我的模块(使用config
),以便将test
选项设置为真值,则导出将另外包含一个__test
符号,其中包含我在测试模块时要导出的一些附加项目。否则,这些符号将不可用。
编辑:如果上述第一种方法让您感到困扰的是必须在所有对内部函数的调用前加上exports
,您可以执行以下操作:
define(["module"], function (module) {
"use strict";
var debug = module.config().debug;
var exports = {};
/**
* @function
* @param {String} name Name of the function to export
* @param {Function} f Function to export.
* @returns {Function} A wrapper for <code>f</code>, or <code>f</code>.
*/
var _dynamic = (debug ?
function (name, f) {
exports[name] = f;
return function () {
// This call allows for future changes to arguments passed..
return exports[name].apply(this, arguments);
};
} :
_dynamic = function (name, f) { return f; });
var foo = function () {
return bar(1, 2, 3);
};
var bar = _dynamic("bar", function (a, b, c) {
return "original: called with " + a + " " + b + " " + c;
});
exports.foo = foo;
return exports;
});
当 RequireJS 配置将上面的模块配置debug
为 true 时,它会导出被包装的函数_dynamic
并提供本地符号,允许在不经过exports
. 如果debug
为 false,则该函数不会被导出并且不会被包装。我已更新示例以显示此方法。它moduleB
在示例中。