常见的是使用以下习惯用法定义了CommonJS模块:
(function() {
var logThis = function() { console.log(this); }
module.exports = logThis;
}).call(this);
我只花了半个小时与同事讨论为什么他们用call(this)调用闭包.这将导致闭包内部的this的值从调用方继承,而不是被设置为全局对象.但是,当我在Node.js中进行测试时,即使在我这样加载并运行它时,模块内部的值始终是全局对象:
var bar = {};
bar.foo = function() { var foo = require("./foo"); foo(); }
我确实希望在控制台中看到bar对象,但实际上我看到了全局对象.然后我想到这可能是因为在Web上下文中也使用了Underscore.js之类的模块.但是在那种情况下,它会加载< script>标记,因此无论如何这将始终等于全局对象.
是什么赋予了?我确定使用此构造是有原因的,但是无论在Node.js还是在网页中使用该模块,在这种特殊情况下我都看不到实际的区别.
更新:为澄清起见,我可以想到许多情况可能会有所作为.例如,如果我说:
var bar = {}
var foo = require("./foo");
bar.foo = foo;
bar.foo();
(感谢@Pointy纠正了我的原始示例.)
我希望在调用require()时对模块中的闭包进行评估,这意味着其内部的值将绑定到全局对象,即使随后调用foo()也会将其写入控制台.作为“ bar”对象的成员.但是,即使在此示例中,我也在控制台中看到了“ bar”对象.我猜这不是像我期望的那样被绑定吗?
简而言之,我正在寻找一个示例,其中像Underscore.js这样的模块由于包裹在用fn.call(this)而不是仅在fn()中调用的闭包中而具有不同的行为,无论是在Node.js还是在在网页中.
解决方法:
您在“ bar.foo”中对“ foo”的调用没有任何上下文,因此使用了全局上下文.它在一个函数内部,该函数引用“条”是不相关的;那不是JavaScript的工作方式.唯一重要的是函数的调用方式,而不是调用位置.
如果“ bar.foo”看起来像这样:
bar.foo = function() { require("./foo"); foo.call(this); }
然后您会在控制台中看到“栏”.或者,您可以这样做:
var bar = {};
require("./foo");
bar.foo = foo;
然后调用bar.foo()还将记录“ bar”对象. (这真的在Node中起作用吗?就是说,我认为require()返回了一个对象,并且它不仅使事物处于全局范围内.但是,我是Node的高级新手.)
编辑-确定,谢谢您的更新.因此,我的示例将按以下方式更正.首先,我认为您的模块应如下所示:
(function() {
var logThis = function() { console.log(this); }
module.exports.logThis = logThis;
}).call(this);
也就是说,我认为您想展开“ logThis”函数,因此需要将其作为命名属性绑定到“ exports”对象.
然后:
var bar = {};
var foo = require("./foo");
// At this point, foo.logThis is the function
bar.foo = foo.logThis;
// Now the "foo" property of "bar" is a reference to the same function
bar.foo(); // logs the "bar" object
var fee = { fie: foo.logThis };
fee.fie(); // logs the "fee" object