2013-06-18 46 views
0

我一直在试验如何将方法和变量附加到具有自我调用匿名函数的对象上,并遇到一些我不明白的行为。是什么导致了这种行为? (Closures&References)

我在函数前定义变量并将其作为参数传入,方法附加到引用,但在外部,name保持未定义状态。

var name; 
(function(exports) { 
    exports = {}; 
    exports.method = function() { 
     // do stuff 
    }; 
})(name); 

alert(name === undefined); // true 

但是,当变量初始化函数外部,而不是正确的属性附加为我所期望的内部。

var name2 = {}; 
(function(exports) { 
    exports.method = function() { 
     // do stuff 
    }; 
})(name2); 

alert(name2 === undefined); // false 
alert(name2.method); // method is defined 

为什么?

+0

我在回答自己的问题时没有问题,但为什么你在问题中写下'我不明白' – bugwheels94

+3

他很快就学会了......? – Teemu

+0

是的,我在完成问题后就明白了。 –

回答

3

将函数作用域外部的对象作为参数传递给自执行函数的技巧对于闭包来说非常方便,而对闭包的作用就在于对外部对象的引用(在第一个示例中存储在name中的参考)通过副本传递(即参考副本)。

通过引用副本对对象所做的任何更改都会影响函数E.g.之外的效果。在你的第二个例子中

exports.method = function() { 
    // do stuff 
}; 

向由name2标识的对象添加一个方法。 但是如果忽略参考的参数保存您在

exports = {} 

做然后你只是存储在同一个变量一个新的引用,用来保存(副本)原件备查

的在诸如使用闭包和迭代变量时需要复制技巧,例如

var i; 
for(i=0,;i<10;i++){ 
    setTimeout(function(){console.log(i)},3000); 
} 

将打印9十倍 而

var i; 
for(i=0,;i<10;i++){ 
    setTimeout((function(i){return function(){console.log(i)};})(i),3000); 
} 

将打印0,1,2,3,4,5,6,7,8,9

+0

很好的答案和很棒的例子。干杯! –

3

因为对象是通过引用传递的,而未定义的变量则不是。

+4

不,'undefined'也是一个对象引用。你只是用另一个覆盖引用。 – Quentin

+5

实际上,对象作为引用的_copy_传递给一个函数,这是一个很大的区别。 – Teemu

+0

@Quentin'undefined'不是一个对象引用,它是一个原始值类型。那么..你可以说这是一个不可解析的参考('IsUnresolvableReference' - true),但这听起来很不直观。丹 - 当你传递一个参考值时,所有东西都会被有价值地传递。这就是为什么'var a = {a:3};(function(x){x = {b:5})(a); a;'会返回'{a:3}'。 –

2

在第一示例,用新对象覆盖对象的副本,然后为其分配一个方法。该对象和方法在函数外部不可用。

在第二个示例中,您将变量定义为该函数之外的对象,并且没有用新对象覆盖引用。因此,该方法被连接到在通过了对象

如果要创建在其中定义函数外的变量的第三示例,然后覆盖参考给它的函数的内部 -

var name3 = {}; 
(function(exports) { 
    exports = {}; 
    exports.method = function() { 
     // do stuff 
    }; 
})(name); 

- 您会发现该方法再次未定义。直到您指定的“出口”指向一个空对象,但“名”仍然是指向不确定

console.log(name === undefined); // false 
console.log(name.method); // undefined 
+0

在示例中没有关闭,因为所讨论的对象作为参数传递给函数,而我的意思是“将对象赋值给变量”而不是“将变量定义为对象”,因为您无法定义一个变量作为一个对象。 –

+0

是的,我正在编辑过程中,当你评论时被别人打断。 –

0

在第一个例子“名”和“出口”共享指针不确定的。

在第二个示例中,“name”和“exports”共享一个指向对象的指针。稍后该对象被修改为具有新属性,但这两个变量的指针仍然相同。

相关问题