为什么这些数组按值传递而不是按引用传递?
Why are these arrays getting passed by value and not by reference?
我正在尝试一些设计模式(Module Reveal 和 Singleton 模式),其中的基本内容按预期工作,例如与多个对象共享的两个实用函数,其中一个更新 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");
b
和 c
的 "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.
我正在尝试一些设计模式(Module Reveal 和 Singleton 模式),其中的基本内容按预期工作,例如与多个对象共享的两个实用函数,其中一个更新 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");
b
和 c
的 "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.