javascript闭包和对象引用

时间:2013-12-26 19:46:06

标签: javascript closures

我有点模糊不清的情况。主要是因为我认为我已经掌握了封闭。基本上我想要的是重置为集合的默认值。所以,假设我的集合中包含带有数组对象参数的构造函数。

 var c = new collection([{x},{y},{z}]);

然后收集定期更新。因为我没有保留数组的初始值,有时我想重置为初始值。

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

所以我可能会想到使用闭包来捕获这个初始值,所以它可能看起来像这样。

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

    return function(){

          c.internalarray = arr;

    }

 })(c.internalarray))

所以它不起作用似乎是因为引用作为参数传递集合更新被禁止的 arr 也得到更新它的结束总是为

arr === c.internalarray;

我可能会想要传递数组的克隆,但重点不在于只是通过分配保持全局变量来创建数据副本。

所以我的问题是我做错了什么。我认为以某种方式隐式javascript引擎创建了一个被困变量/对象的副本。我没有必要跟踪它们。

2 个答案:

答案 0 :(得分:0)

在javascript中,复合数据类型通过引用传递,因此c.internalarrayarr都引用相同的值。实际上,你是在正确的方式,但你必须先复制数组,然后再将它传递给你立即调用的函数。例如:

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删除第一个元素对b

没有影响
a.shift();
// a -> [{}]
// b -> [1, {}]

但是修改a中包含的对象也会影响b

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

答案 1 :(得分:0)

这与闭包无关。用这个可以看出你的问题更简单:

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的值是指向对象的指针等。具体在此case,c.internalarray是指向数组对象的指针。将一个指针指向另一个指针只会使第二个指针指向第一个指向的对象。执行arr = internalarray;时(或在代码中,当您将c.internalarray作为参数arr传递给函数时),您有两个指向同一对象的指针。

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