2012-01-09 16 views
5

基本例如:Javascript的分配操作是复制引用?

var b = 10; 
var c = b; 
b++; 
console.log(b,c); 

>> 11 10 

c貌似b副本。

但在另一种情况:

var x = {}; 
var y = x; 
x.abc = 10; 
console.log(x.abc, y.abc); 

>> 10 10 

为什么y不是x副本,但指向同一个实例x指向一个参考?

此外,我猜想b++创建另一个实例,所以b指向新的实例,但c指向旧的实例。然而...

var u = 10; 
setTimeout(function() { 
    console.log(u); 
}, 10000) 
u++; 

>> 11 

如果u++匿名函数内部创建一个新的实例,那么u应指向旧u,不应该吗?

回答

9

c看起来像b的副本。

两者都是对同一个不可变值的引用。

为什么y是不可复制的x但指向实例的引用x点?

x是首先对一个对象的引用,所以y是它的一个副本(基准的副本,而不是对象的副本)。

如果u++创建一个新的实例,

事实并非如此。

u在匿名函数中应该指向旧的u,应该不是吗?

u++将对11的引用赋予u。匿名函数查看的是u,而不是“函数创建时的值u”。

+0

你最后一句话实际上解决了我的困惑 – 2012-01-09 17:33:41

+1

@Quentin:原来的“对象”只是驻留在由js-implementation(ES3/5)创建的'激活对象'或'词法环境'中的某个地方,并且永远不会真正被E CMAscript本身。 – jAndy 2012-01-09 17:36:37

+0

“两者都是对同一个不变值的引用。”这与观察到的产量“11 10”不矛盾吗?输出会表明它们是对不同值的引用 – Neptilo 2018-02-11 22:21:17

8

当原语被分配时,它们被赋值为,值为;引用类型(如您的对象)被分配引用(或者,如Jon Skeet纠正我,他们被分配了参考副本)。

在你的第二个例子中x和y都是指向内存中的同一个对象。这就是为什么添加abc属性之一,也是其添加到其他

你想也遵守同样的行为,通过X或Y为功能

function addABC(foo) { 
    foo.abc = 10; 
} 

var x = {}; 
var y = x; 
addABC(x); 
console.log(x.abc, y.abc); 

只要注意的是,尽管X和Y点在存储器中的相同的对象,它们是参考的单独的副本,所以这

var x = { a: 1 }; 
    var y = x; 
    y = {}; 
    alert(x.a); 

var x = { a: 1 }; 
    var y = x; 
    x = {}; 
    alert(y.a); 

仍然会提醒1.

+1

我不喜欢这里的“通过引用”的术语 - 因为*真正的“通过引用或通过引用复制有些不同,例如,假设你将'addABC'方法改为'foo =“hello”,那不会改变'x'的值,是不是?(无可否认,我假设JavaScript的作用与Java和C#相同,但我认为这是一个合理的假设。) – 2012-01-09 17:26:11

+0

@Jon - 你是对的,我会编辑 – 2012-01-09 17:29:04

4

本声明:

var y = x; 

副本为y初始值的x值。但是,所涉及的值是参考到一个对象,而不是对象本身。请注意,这是而不是就像说这个任务复制了“对x的引用” - 它确实是的值x。特别是,如果您将x的值更改为引用不同的对象,例如

x = "something else"; 

那么将不会改变的y值 - 其值仍然是原来的对象的引用。

+1

Jon Skeet?!?!在JavaScript标记中?!?!欢迎您,好先生! – 2012-01-09 17:22:28

+3

@AdamRackis:他在这个池塘里蘸了他的脚趾前 – 2012-01-09 17:29:33