变量赋值在JavaScript中是如何工作的?

变量赋值在JavaScript中是如何工作的?,javascript,Javascript,所以前几天我只是想看看大规模赋值在JavaScript中是如何工作的 首先,我在控制台中尝试了这个示例: a = b = {}; a.foo = 'bar'; console.log(b.foo); 结果是“条形图”显示在警报中。这很公平,a和b实际上只是同一对象的别名。然后我想,我怎样才能使这个例子更简单 a = b = 'foo'; a = 'bar'; console.log(b); 这几乎是一回事,不是吗?这一次,它返回foo而不是bar,正如我从第一个示例的行为中所期望的那样 为什

所以前几天我只是想看看大规模赋值在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’;

控制台日志(b)您或多或少是正确的,只是您所指的“哈希”实际上只是对象的简写语法


在第一个示例中,a和b都引用同一个对象。在第二个示例中,您将a更改为引用其他对象。

您将a设置为指向新的字符串对象,而b保持指向旧的字符串对象。

在第一种情况下,您更改变量中包含的对象的某些属性,在第二种情况下,您为变量指定新值。这是根本不同的事情。变量
a
b
不是通过第一个赋值以某种方式神奇地链接起来的,它们只是包含相同的对象。在第二个示例中也是如此,直到您为
b
变量指定一个新值。

在第一个示例中,您正在设置现有对象的属性。在第二个示例中,您正在指定一个全新的对象

a = b = {};
a
b
现在是指向同一对象的指针。所以当你这样做的时候:

a.foo = 'bar';
它还设置了
b.foo
,因为
a
b
指向同一个对象

然而

如果您改为这样做:

a = 'bar';
您是说
a
现在指向另一个对象。这对
a
之前指向的内容没有影响

在JavaScript中,分配变量和分配属性是两种不同的操作。最好将变量视为指向对象的指针,当您直接为变量赋值时,您不会修改任何对象,只会将变量重新写入另一个对象


但是指定一个属性,如
a.foo
,将修改
a
指向的对象。当然,这也会修改指向此对象的所有其他引用,因为它们都指向同一个对象。

简单类型和对象之间的区别

任何对象(如数组或函数)都是通过引用传递的

任何简单类型(如字符串或数字)都会被复制


我手头总是有一个copyArray函数,所以我可以确定我没有为同一个数组创建一堆别名。

你的问题已经被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

以下是我的答案:

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

那么,为什么要对客体采取双重标准呢?这不是双重标准。在第一个示例中,a和b仍然引用同一个对象,您只是在修改该对象的属性。在第二个示例中,您将a指向另一个对象。不,区别在于,在第二个示例中,您处理的是一个字符串,而不是一个对象。需要明确的是:这与字符串返回自身副本无关。这两个代码片段不同的原因在Kevin的第二段(在Squeegy的回答中有更全面的解释)中。变量中是否有字符串或对象并不重要。你分配了一个新的不同的值,然后变量包含了这个新的不同的值。“你是说a现在指向一个不同的对象。”不,不要使用“对象”这个词。字符串不是JavaScript中的对象。从技术上讲,字符串可能不是JavaScript类型“object”,但它们可以被认为是OO意义上的对象。@Squeegy:字符串是基本体,而不是对象:不能为字符串指定任意属性!它们的行为仅类似于对象,因为在Java中称之为自动装箱,但字符串具有方法和属性,并且字符串的原型肯定可以修改。它们的行为确实像物体一样。@ddlshack:正如克里斯托夫所解释的,这是由于自动装箱。如果要通过
var foo=new string('foo')定义字符串
,那么这将是一个字符串对象(并且
typeof
将确认这一点)。但是如果您通过字符串文字声明它,那么它们就是字符串原语。看:区别不是没有