是什么导致这种行为? (闭包和参考)

时间:2013-06-18 10:50:44

标签: javascript

我一直在尝试使用自动调用匿名函数将方法和变量附加到对象的方法,并遇到一些我不理解的行为。

我在函数之前定义变量并将其作为参数传递,方法附加到引用,但在外部,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

为什么?

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

将一个对象从函数作用域外部作为参数传递给自执行函数的技巧在闭包时很方便,对闭包有效的是对外部对象的引用(在你的第一个例子中)存储在name)中的引用通过副本传递(即引用的副本)。

通过引用副本对对象的任何更改都将在函数E.g之外生效。在你的第二个例子中

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

为name2标识的对象添加方法。 但是,如果您像在

中那样覆盖参数保持的引用
exports = {}

然后,您只是将新引用存储在用于保存(副本)原始引用的同一变量中

有时需要复制技巧,例如使用闭包和迭代变量时 e.g。

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

答案 2 :(得分:2)

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

在第二个示例中,您将变量定义为函数外部的对象,并且未使用新对象覆盖引用。因此,该方法附加到传入的对象。

如果您要创建第三个示例,在该示例中定义函数外部的变量,然后在函数内部覆盖对它的引用 -

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

- 您会发现该方法再次未定义。

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

答案 3 :(得分:0)

在第一个示例中,“name”和“exports”共享指向undefined的指针,直到您指定“exports”指向空对象,但“name”仍然指向undefined。

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