2012-08-01 66 views
3

这经常可以看到使用以下定义成语模块CommonJS的时():fn.call(本)与FN限定CommonJS的模块

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

Underscore.js,例如,执行此操作。

我只花了半个小时与一位同事讨论他们为什么要用call(this)来调用关闭。这将导致闭包内的this的值从调用者继承,而不是被设置为全局对象。然而,当我在Node.js的测试这一点,this模块内部的pH值总是全局对象,甚至当我加载并运行它像这样:

var bar = {}; 
bar.foo = function() { var foo = require("./foo"); foo(); } 

我真的很期待看到bar对象在控制台中,但实际上我看到了全局对象。然后,我想这可能是因为像Underscore.js这样的模块也被用在web上下文中。但在这种情况下,它将加载<脚本>标记,因此this总是等于全局对象。

什么给?我确信有一个使用这个构造的理由,但是在这个特殊情况下我看不出这个模块是在Node.js中还是在网页中使用。

更新:只是为了澄清,我能想到的一些情况下,这可能有所作为的。例如,如果我说:

var bar = {} 
var foo = require("./foo"); 
bar.foo = foo; 
bar.foo(); 

(感谢@Pointy纠正我原来的例子)

我希望模块在封闭进行评估时require()被调用,这意味着值this内部将被绑定到全局对象,该对象将被写入控制台,即使foo()然后被调用为“bar”对象的成员。然而,即使在这个例子中,我也看到了控制台中的“bar”对象。我猜想this没有像我期望的那样被绑定到闭包?

概括地说,我正在寻找一个例子像Underscore.js一个模块都会有不同的行为,由于被包裹在与fn.call(this),而不只是fn()调用的关闭,无论是在Node.js的或网络页。

+0

确定我会更新我的答案... – Pointy 2012-08-01 17:16:29

回答

4

您在“bar.foo”中调用“foo”时没有任何上下文,因此将使用全局上下文。它在this引用“bar”的函数中并不相关;这不仅仅是JavaScript的工作原理。唯一重要的是函数如何被调用,而不是,其中被调用,换句话说。

如果 “bar.foo” 是这样的:

bar.foo = function() { require("./foo"); foo.call(this); } 

,那么你会看到 “酒吧” 在控制台中。或者,你可以这样做:

var bar = {}; 
require("./foo"); 
bar.foo = foo; 

然后调用bar.foo()也将记录在“酒吧”的对象。 (这是否真的在节点中工作?也就是说,我认为require()返回了一个对象,并且它不只是把东西留在全局范围内。然而,我是Node的排名新手。)

编辑 —好的感谢您的更新。因此,我的例子将被纠正如下。首先,我认为你的模块应该是这样的:

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

也就是说,我认为你要explort了“logThis”的功能,因此需要将其绑定到“出口”对象作为命名属性。

然后:

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 
+0

你可以说:'bar.foo =要求( “./富”);'你说得对,我是用错误的'this'调用'foo()'。然而,这仍然不能回答我的问题,因为当我改变模块使用'(function(){...})();'而不是'(function(){...})。 )',当我调用'bar.foo();'时,我仍然看到“bar”对象。在这种情况下,我确实希望看到全局对象。所以我仍不清楚这两种构造在这种情况下的差异。 – 2012-08-01 16:55:34

+0

哦,你是对的,我的代码示例包含一个错字。我纠正了它,以便'require()'返回的值被赋值给一个变量'foo'。 – 2012-08-01 16:59:06

+0

更新了问题以解释为什么这不能完全回答它。 – 2012-08-01 17:08:47

相关问题