为什么这些数组按值传递而不是按引用传递?

Why are these arrays getting passed by value and not by reference?

我正在尝试一些设计模式(Module RevealSingleton 模式),其中的基本内容按预期工作,例如与多个对象共享的两个实用函数,其中一个更新 String 的值,另一个复制 String 的值。

当我将字符串转换为数组时发生了意想不到的事情,期望它通过引用传递,但由于某种原因没有实现:

Test.js

(function(win){
    var MainObj=(function(){
        var _alls = Object.create(null);

        function u_updateVal(){
            this.arr = ["up", "da", "ted"];
        }

        function u_copyVal(oName, prop){
            this[prop] = _alls[oName][prop];
        }

        function init(oName){
            if(typeof _alls[oName]==="undefined"){
                _alls[oName] = {
                    arr : ["def", "ault"],
                    updateVal : u_updateVal,
                    copyVal : u_copyVal
                };
            }

            return _alls[oName];
        }

        return {
            init : init
        };
    })();

    if(!win.MainObj){
        win.MainObj = MainObj;
    }
})(window);

来自 HTML 的 plain-js,取决于:Test.js

if(!window.MainObj){
    console.log("Error: MainObj is not defined");
}else{
    var a = MainObj.init("AA");
    var b = MainObj.init("BB");
    var c = MainObj.init("CC");

    b.updateVal();
    c.copyVal("BB", "arr");
    b.arr=["over", "written"];

    console.log(a.arr.join()); //def,ault
    console.log(b.arr.join()); //over,written
    console.log(c.arr.join()); //up,da,ted (I expected "over,written")
}

我希望 c.arr 指向与 b.arr 相同的引用,因为数组的副本没有像 splice/slice/JSONstringify/etc.

这样的任何预防措施

为了改变一些事情,我创建了另一个函数来通过 b.otherUpdateVal(); 而不是 b.arr = ["over", "written"]; 更新值,希望它与闭包有关,超出我目前的理解他们,但这仍然给出相同的结果。

我似乎无法理解为什么这些数组没有通过引用传递(即使没有采取特殊措施来防止这种情况发生)。想知道为什么会这样吗?

编辑: 是的,这只是一个愚蠢的疏忽,认为重新分配 b 会影响已完成的 c 引用。如果您使用 b.arr.push("."); 或排序,或任何实际上不会创建全新数组的东西,您确实会看到它们都受到影响。

在此之后:

c.copyVal("BB", "arr");

bc 的 "arr" 属性的值将是对同一数组的引用。然而,在此之后:

b.arr=["over", "written"];

您已经覆盖了 "arr" 属性 的值。这对 c.arr.

的值没有任何影响

让我们逐步了解会发生什么。

var a = MainObj.init("AA");
var b = MainObj.init("BB");
var c = MainObj.init("CC");

完成这一步后你就拥有了。

a.arr; // ["def", "ault"]
b.arr; // ["def", "ault"]
c.arr; // ["def", "ault"]

那我们改b.

b.updateVal();

其他不变,b更新了

b.arr; // ["up", "da", "ted"]

然后您在 copyVal 函数中将相同的 b.arr 引用分配给 c.arr

this[prop] = _alls[oName][prop]; // Copy the reference.

您的最终更改创建了一个完整的 new 数组并将其分配给 b.

b.arr=["over", "written"];

你得到了。

a.arr; // ["def", "ault"]
b.arr; // ["over", "written"] a new array you've created in the final step.
c.arr; // ["up", "da", "ted"] which is the old b array still being referenced.