变量赋值在JavaScript中是如何工作的?
所以前几天我只是想看看大规模赋值在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,正如我从第一个示例的行为中所期望的那样 为什
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
将确认这一点)。但是如果您通过字符串文字声明它,那么它们就是字符串原语。看:区别不是没有