所以我前几天正在玩,只是为了确切了解大规模分配在JavaScript中是如何运作的。
首先我在控制台中尝试了这个例子:
a = b = {};
a.foo = 'bar';
console.log(b.foo);
结果是“警报”显示在警报中。这很公平,a
和b
实际上只是同一对象的别名。然后我想,我怎么能让这个例子更简单。
a = b = 'foo';
a = 'bar';
console.log(b);
这几乎是一回事,不是吗?那么这一次,它会返回foo
而非bar
,正如我对第一个例子的行为所期望的那样。
为什么会这样?
N.B。使用以下代码可以简化此示例:
a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);
a = 'foo';
b = a;
a = 'bar';
console.log(b);
(我怀疑JavaScript将字符串和整数等原语与哈希值区别对待。哈希值返回指针,而“核心”原语返回自己的副本)
答案 0 :(得分:109)
在第一个示例中,您要设置现有对象的属性。在第二个示例中,您要分配一个全新的对象。
a = b = {};
a
和b
现在指向同一个对象。所以当你这样做时:
a.foo = 'bar';
它设置了b.foo
,因为a
和b
指向同一个对象。
但是!的
如果你这样做:
a = 'bar';
你说现在a
指向另一个对象。这对a
之前指出的内容没有影响。
在JavaScript中,分配变量和分配属性是两种不同的操作。最好将变量视为对象的指针,当您直接赋值给变量时,您不会修改任何对象,只需将变量重新分配给不同的对象。
但是,分配属性(如a.foo
)将修改a
指向的对象。当然,这也会修改指向此对象的所有其他引用,因为它们都指向同一个对象。
答案 1 :(得分:26)
你的问题已经被Squeegy满意地回答了 - 它与对象与原语无关,而是在同一引用对象中重新分配变量与设置属性。
答案和评论中似乎有很多关于JavaScript类型的混淆,所以这里是对JavaScript类型系统的一个小介绍:
在JavaScript中,有两种根本不同的值:基元和对象(并且没有“哈希”这样的东西)。
字符串,数字和布尔值以及null
和undefined
都是基元,对象是可以拥有属性的所有内容。甚至数组和函数也是常规对象,因此可以保存任意属性。它们只是内部[[Class]]属性不同(函数还有一个名为[[Call]]和[[Construct]]的属性,但是嘿,这是详细信息。)
原始值可能表现得像对象的原因是因为自动装箱,但原语本身不能保存任何属性。
以下是一个例子:
var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);
这将输出undefined
:a
包含原始值,在分配属性foo
时会将其提升为对象。但是这个新对象会立即被丢弃,因此foo
的值会丢失。
这样想:
var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created
答案 2 :(得分:2)
你或多或少是正确的,除了你所谓的“哈希”实际上只是对象的简写语法。
在第一个示例中, a 和 b 都引用同一个对象。在第二个示例中,您更改 a 以引用其他内容。
答案 3 :(得分:2)
这是我的答案版本:
obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"
// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"
// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory
答案 4 :(得分:0)
您将a设置为指向新的字符串对象,而b则指向旧的字符串对象。
答案 5 :(得分:0)
在第一种情况下,您更改变量中包含的对象的某些属性,在第二种情况下,您为变量指定一个新值。这是根本不同的事情。变量a
和b
在某种程度上不是由第一个赋值神奇地链接,它们只包含相同的对象。在第二个示例中也是这种情况,直到您为b
变量分配新值。
答案 6 :(得分:0)
区别在于简单类型和对象。
任何对象(如数组或函数)都通过引用传递。
复制任何简单类型(如字符串或数字)。
我总是有一个方便的copyArray函数,所以我可以确定我没有为同一个数组创建一堆别名。