0

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

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

4 回答 4

3

当涉及到闭包时,将函数范围外的对象作为参数传递给自执行函数的技巧很方便,而闭包的作用是对外部对象的引用(在您的第一个示例中,引用存储在name) 通过副本传递(即引用的副本)。

通过引用的副本对对象进行的任何更改都将在函数之外产生影响,例如在您的第二个示例中

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

于 2013-06-18T11:24:42.847 回答
3

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

于 2013-06-18T10:50:44.027 回答
2

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

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

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

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

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

console.log(name === undefined); // false
console.log(name.method); // undefined
于 2013-06-18T11:25:44.447 回答
0

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

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

于 2013-06-18T11:40:23.910 回答