javascript-定义CommonJS模块时fn.call(this)与fn()

常见的是使用以下习惯用法定义了CommonJS模块:

(function() {
   var logThis = function() { console.log(this); }
   module.exports = logThis;
}).call(this);

例如Underscore.js.

我只花了半个小时与同事讨论为什么他们用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
上一篇:javascript-ES6模块的“导入”正式与CommonJS和AMD兼容吗?


下一篇:Node学习之----模块机制篇