javascript闭包和对象引用

javascript闭包和对象引用,javascript,closures,Javascript,Closures,我的处境有点模糊。主要是因为我认为我已经掌握了闭包。所以基本上我想要的是将集合重置为默认值。假设我有一个集合,它有一个构造函数和一个对象数组参数 var c = new collection([{x},{y},{z}]); 然后定期更新集合。因为我并没有保留数组的初始值,过了一段时间我想重置为初始值 现在我不是在问如何实现这一点,关于闭包本身,我的问题可能有多种方式。请进一步阅读 因此,我可能会想到使用闭包捕获这个初始值的方法,所以它看起来可能是这样的 c.on('reset',(funct

我的处境有点模糊。主要是因为我认为我已经掌握了闭包。所以基本上我想要的是将集合重置为默认值。假设我有一个集合,它有一个构造函数和一个对象数组参数

 var c = new collection([{x},{y},{z}]);
然后定期更新集合。因为我并没有保留数组的初始值,过了一段时间我想重置为初始值

现在我不是在问如何实现这一点,关于闭包本身,我的问题可能有多种方式。请进一步阅读

因此,我可能会想到使用闭包捕获这个初始值的方法,所以它看起来可能是这样的

c.on('reset',(function(arr){

    return function(){

          c.internalarray = arr;

    }

 })(c.internalarray))
因此,它似乎不起作用,因为引用是作为参数传递的,集合更新了受支持的被捕获的arr也得到了更新,其最终结果始终为true

arr === c.internalarray;
我可能想传递数组的克隆,但重点不是在某个地方创建一个带有全局变量的数据副本


所以我的问题是我做错了什么。我认为javascript引擎以某种方式隐式地创建了一个被捕获的变量/对象的副本。在javascript中,复合数据类型是通过引用传递的,因此,
c.internalarray
arr
都引用相同的值。实际上,您的方法是正确的,但是在将数组传递给立即调用的函数之前,您必须创建数组的副本。例如:

c.on('reset', function (arr) {
    return function () {
        c.internalarray = arr;
    }
}(c.internalarray.slice()));
这就是说,这种技术不会创建深度副本,这意味着数组中包含的复合类型仍然可以从立即调用的函数外部进行修改。在下面的代码中,我试图简化这种情况,以便更容易理解,希望:

变量
a
表示包含两个元素的数组:

var a = [
    1, // primitive value
    {} // composite value
];
让我们制作一个
a
的浅拷贝,并将其分配给
b

var b = a.slice();
// a -> [1, {}]
// b -> [1, {}]
// b === a -> false
a.shift();
// a -> [{}]
// b -> [1, {}]
a
中删除第一个元素对
b
没有影响:

var b = a.slice();
// a -> [1, {}]
// b -> [1, {}]
// b === a -> false
a.shift();
// a -> [{}]
// b -> [1, {}]
但是修改
a
中包含的对象也会影响
b

a[0].k = 'value';
// a -> [{ k: "value" }]
// b -> [1, { k: "value" }]
// a[0] === b[1] -> true

这与闭包无关。您的问题可以通过以下方式更简单地看到:

var internalarray = [{x},{y},{z}];
var arr = internalarray;

// "update" internalarray here

arr === internalarray // still true
internalarray = arr; // This statement has no effect
就像在Java中一样,JavaScript中的每个值要么是原语,要么是引用(指向对象的指针)。
arr
的值是指向对象的指针,
c
的值是指向对象的指针,
c.internalarray
的值是指向对象的指针,等等。在这种情况下,
c.internalarray
是指向数组对象的指针。将一个指针指定给另一个指针只会使第二个指针指向第一个指针指向的对象。当您执行
arr=internalarray时
(或者在代码中,当您将
c.internalarray
作为参数
arr
传递给函数时,您有两个指向同一对象的指针


当您说“定期更新集合”时,您永远不会将(如
=
)分配给
c.internalarray
本身。这就是为什么
arr===c.internalarray
保持为真的原因——因为您最初将一个数组分配给了另一个数组,所以它们不相等的唯一方法是您稍后分配给其中一个数组。相反,我猜您正在更改这两个变量所指向的数组元素,使用下标操作符,如
c.internalarray[foo]=bar
或调用类似
c.internalarray.push(bar)的方法。由于您正在更改指向的对象,多个指向该对象的指针将能够看到更改。

感谢您的澄清。我有点心碎。我还期待着更多。就我从你的帖子中了解到的操作系统而言,闭包只有在使用某种值类型时才有意义?众所周知的泛在循环示例很适合使用递增值类型。如果它对引用类型不起作用,那么我可以给它分配一些临时变量。@mobygeek闭包是关于变量值的。对对象(或数组)的引用本身就是一个值。这就是在闭包中保存下来的东西。但是,任何对象或数组的内容都可以更改,因为JavaScript对象是可变的。不管是否涉及结案,这都是事实。如果要保存对象的内容,必须显式执行。@mobygeek“闭包只有在使用某些v̶a̶l̶u̶e̶基元类型时才有意义”,而不是“闭包让您将某些数据与对该数据进行操作的函数相关联”(),这是它的主要用途,无论此数据的基本/复合性质如何。在您的情况下,闭包对于对象的深度副本仍然很有用。事实上,它能够存储数据供以后使用,而不需要更复杂的面向对象的样式,也不污染上层作用域。好的,newacct,感谢您的贡献。我的缺点是我使用了“通过引用传递”这个词,你是对的,我必须清楚地表明,这意味着通过值传递引用。我清楚地理解什么是引用,什么是价值。我不希望在javascript中看到像c#中的“ref”关键字这样的东西。不管怎样,我最初认为,即使我通过值传递引用(引用的副本而不是对象),引擎也会创建它的某种深度副本,并将其保存在闭包中。这就是我的印象。就这些,似乎没有,有很多关于炒作结束的事情。我们通常每天都用其他语言来做。因此,如果我错了,请纠正。如果您计划破坏/忘记原始值,则闭包是有用的。因此,由于有一个闭包(您的内部函数引用),它将为您挂起。但如果你不打算丢弃原版,那么它们是相同的。没有必要依赖闭包。@mobygeek:在这种情况下,没有必要使用闭包来分配
arr
(c.intern的原始值)