如果模块中的函数直接调用模块的其他函数(即通过使用模块本地的引用),则无法在外部拦截 这些 调用。但是,如果您更改模块以使其 inside 函数以与代码 outside 相同的方式调用模块的函数,那么您可以拦截这些调用。
这里有一个例子可以满足你的需要:
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而不是直接调用。
我提出了一个可运行的示例here。 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 为假,则该函数不会被导出并且不会被包装。我更新了example 来展示这个方法。示例中为moduleB。