是什么导致了这种行为?(闭包,引用)

What causes this behaviour? (Closures & References)

本文关键字:闭包 引用 是什么      更新时间:2023-09-26

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

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

为什么?

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

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

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

向由name2标识的对象添加一个方法。但是,如果像在

中那样重写形参保存的引用
exports = {}

那么您只是将一个新引用存储在用于保存原始引用

(副本)的相同变量中。在使用闭包和迭代变量等情况下,需要使用复制技巧例如
var i;
for(i=0,;i<10;i++){
  setTimeout(function(){console.log(i)},3000);
}

将打印9 10次而

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

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

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

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

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

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

——你会发现这个方法还是未定义的。

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

在第一个例子中,"name"answers"exports"共享一个指向undefined的指针,直到你指定"exports"指向一个空对象,但"name"仍然指向undefined。

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