var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b[0] = 1;
alert(a[0] + ' ' + b[0]);
}
why();
结果是a[0]=1, b[0]=1;
。好像JavaScript是通过引用传递的?
但在这种情况下:
var a = [3, 4, 5];
var b = [6, 7, 8];
function why() {
b = a;
b = [1, 2, 3];
alert(a + ' ' + b);
}
why();
结果为a=[3,4,5]
和b = [1,2,3]
。它为什么通过价值?
如何避免通过引用传递?
答案 0 :(得分:6)
与大多数对象语言一样,非原始变量的值是对象的引用。
在第二种情况下,您不是要更改数组,而是更改b
中存储的引用。
如果要复制阵列,请使用
var c = a.slice();
然后c
和a
将独立发展。
答案 1 :(得分:3)
因为这就是变量的工作方式。
在第一种情况下,您将两个变量都设置为一个数组的同一个实例,然后通过b
(b[0] = 1
)修改该数组。您也可以通过a
修改相同的数组,但是点b
和a
指向同一个数组; b
不“指向”a
。
在第二个中,您将两者都设置为一个数组的同一个实例(b = a
),然后将b
设置为全新的实例,不同数组(b = [1,2,3]
)。您正在更改b
指向的数组,但不会影响a
,因为正如我所说,b
未指向a
,它指向与a
相同的值。
答案 2 :(得分:3)
变量b
和a
指向到对象。执行b = // something
时,您正在更改变量指向的位置。你没有改变底层物体。
在第一个代码中,b = a
表示b
和a
现在指向同一个对象。因此,当您对一个进行更改时,它会反映在另一个中。
但是,在第二个示例中,您首先将b
指向与a
相同的对象,但然后将b
指向 new 数组([1,2,3]
)。它在短时间内指向a
这一事实无关紧要。
答案 3 :(得分:3)
这两种情况都是按值传递的。 JavaScript 总是传递值,没有办法通过引用传递。特别是,传递的值始终是指向对象的指针。 (实际上,原语是直接通过值传递的,但只能观察到可变值的差异,而原语是不可变的,所以它没有区别。)
在第一种情况下,您正在改变指针所指向的对象。但是参考不会改变,只有参考指向的对象。引用仍然指向同一个对象,该对象看起来与以前不同。
值传递值的这种特定情况有时被称为逐个对象共享,逐个对象或逐个调用,并且是方式参数传递几乎适用于所有面向对象的语言:Smalltalk,Python,Ruby,Java,C#(默认情况下,您可以通过显式指定ref
修饰符来传递引用)等。
答案 4 :(得分:0)
第一种情况是更改数组项的一个值。 b现在等于a a [0],b [0]给出相同的值。
在第二种情况下,即使你将b指向a,你也为b分配了一个新对象。所以b和a又是两个不同的对象......所以不同的值。
答案 5 :(得分:0)
在所有这些伟大的答案之后,没有更多的话要说,所以继承了基于ECMAScript 5规范的解释。
在答案结尾处也是一个深层克隆功能。
如ES5规范中所定义,
11.13.1 Simple Assignment ( = ) 生产AssignmentExpression:LeftHandSideExpression = AssignmentExpression的计算方法如下:
GetValue(rref)
。 PutValue(lref, rval)
。 当我们到达点 3 并且rref
是一个对象时,发生了什么事,是
§8.7.1(In GetValue(V) //V==rref
的4b节是有趣的观点)
4。 如果是IsPropertyReference(V),那么
现在此时rval
将引用保存到对象,然后将其放入 5。
其中§8.7.2(PutValue(V,W) //V==lref , W==rval
的4b再次是有趣的部分)开始发挥作用。
注意:W是对您要分配的对象的引用,不值
4。 如果是IsPropertyReference(V),那么
正如您在案例中所见,b
的值是对象[6, 7, 8]
的引用被替换为结果可以这么说GetValue(rref)
,这是参考到[1, 2, 3];
显然您正在寻找深度克隆功能
这是一个。
Object.defineProperty(Object.prototype, "clone", {
value: function (deep) {
var type = Object.prototype.toString.call(this).match(/^\[object (.+?)\]$/)[1];
if (type !== "Object") {
return this.valueOf;
}
var clone = {};
if (!deep) {
for (var prp in this) {
clone[prp] = this[prp];
}
} else {
for (var prop in this) {
if (typeof this[prop] !== "undefined" && this[prop] !== null)
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone((typeof deep == "boolean" ? deep : (deep - 1))));
else
clone[prop] = "";
}
}
return clone;
},
enumerable: false
});
Object.defineProperty(Array.prototype, "clone", {
value: function (deep) {
var clone = [];
if (!deep) clone = this.concat();
else this.forEach(function (e) {
if (typeof e !== "undefined" && e !== null)
clone.push((typeof e !== "object" ? e : e.clone((deep - 1))));
else
clone.push("");
});
return clone;
},
enumerable: false
});
var a = [1, [2, { a: 3 } ], 4];
var b = a.clone(Infinity);
a[1][1]["a"] = "cloned";
console.log(a[1][1]["a"], b[1][1]["a"]); //"cloned" , 3
上的演示
要使用它,只需在对象或数组上调用.clone(levelOfDeepness)
注意:为了简单起见,我使用了对象原型,因为我可以在克隆它们的同时直接调用对象和数组元素的.clone
(在单个函数中提供类型检查变量的性能提升)< / em>的