Javascript 指针/引用疯狂。有人可以解释一下吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8318357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript pointer/reference craziness. Can someone explain this?
提问by Philip Walton
Javascript passes objects by reference. This makes perfect sense. But once you start manipulating those objects, everything acts in a way that seem unintuitive. Let me offer an example:
Javascript 通过引用传递对象。这是完全有道理的。但是一旦你开始操纵这些对象,一切都会以一种看起来不直观的方式运行。让我举个例子:
var a, b;
a = {}
b = a;
a['one'] = {};
console.log( JSON.stringify(a) );
// outputs: {"one":{}}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
This is all well and good because now b
has a pointer to a
so it's expected that assigning stuff to a
will also affect b
.
这是一切都很好,因为现在b
有一个指针,a
所以它的预期,到指定的东西a
也会影响b
。
But then if I do this:
但是如果我这样做:
a = a['one'];
console.log( JSON.stringify(a) );
// outputs: {}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
This is surprising to me. I'd expect a
and b
to still be the same (and to be {}
since a['one']
was previously set to {}
and a
was set to a['one']
).
这让我很惊讶。我希望a
并且b
仍然是相同的(并且{}
因为a['one']
之前被设置为{}
并且a
被设置为a['one']
)。
But that's not the case. It appears that a
loses its reference to b
when it's assigned to something new, but b
maintains the value that a
was set to prior to a
loosing its reference to b
.
但事实并非如此。它似乎a
失去了对b
何时分配给新事物的引用,但b
保持了a
在a
失去对b
.
But then if I do this:
但是如果我这样做:
a['two'] = 2;
console.log( JSON.stringify(a) );
// outputs: {"two":2}
console.log( JSON.stringify(b) );
// outputs: {"one":{"two":2}}
What? a
has clearly lost it's reference to b
, but b
seems to still have some reference to a
.
什么?a
显然已经失去了对 的引用b
,但b
似乎仍然有一些对 的引用a
。
Does the empty object {}
point to some place in memory so every variable referencing it is now pointing to the same place?
空对象是否{}
指向内存中的某个位置,因此引用它的每个变量现在都指向同一个位置?
Can someone with a firm grasp on this explain it to me?
对此有深入了解的人可以向我解释一下吗?
回答by Seth Carnegie
Following your example line by line:
逐行按照您的示例进行操作:
a = {}
a
now references the new object.
a
现在引用新对象。
b = a;
b
now references the same object that a
references. Note that it does not reference a
.
b
现在引用与引用相同的对象a
。请注意,它不引用a
.
a['one'] = {};
The new object now has an index 'one'
that references another new object.
新对象现在具有'one'
引用另一个新对象的索引。
When you do
当你做
a = a['one'];
You are setting a
to refer to a['one']
, which is that new object you created when you did a['one'] = {}
. b
still references the object you created with a = {}
.
您正在设置a
为引用a['one']
,即您在创建时创建的新对象a['one'] = {}
。b
仍然引用您创建的对象a = {}
。
You are confusing the issue when you say "a
has lost its reference to b
" because a
does not refer to b
, nor vice versa. a
and b
refer to objects, and they can be made to refer to other objects. Like this:
当你说“a
已经失去了对b
”的引用时,你会混淆这个问题,因为a
不引用b
,反之亦然。a
和b
引用对象,它们可以被用来引用其他对象。像这样:
With a = {}; b = a
, you get
随着a = {}; b = a
,你得到
a
\
\
{ }
/
/
b
Then with a['one'] = {}
you get
然后和a['one'] = {}
你一起得到
a
\
\
{ one: { } }
/
/
b
Then with a = a['one']
you get
然后和a = a['one']
你一起得到
a - - - -
\
{ one: { } }
/
/
b
回答by riwalk
:P You're descending into the knitty gritty details and I'm glad you asked, as you will be wiser by the end.
:P 你正在深入了解细节,我很高兴你问了,因为到最后你会更聪明。
Don't look at it in terms of pointers, because I think that is where you are getting confused. Think of it rather in terms of the heap (or just "memory" if you will) and the symbol table.
不要用指针来看待它,因为我认为这就是你感到困惑的地方。而是从堆(或者只是“内存”,如果你愿意的话)和符号表的角度来考虑它。
Lets start by taking the first few lines of your code:
让我们从代码的前几行开始:
var a, b;
a = {}
b = a;
What you've done here is created one object on the heap and two symbols on the symbol table. It looks something like this:
您在这里所做的是在堆上创建了一个对象,在符号表上创建了两个符号。它看起来像这样:
Symbol Table:
符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
Heap:
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
.
.
Here's where things get interesting: Objects have their own "symbol tables" (usually these are just hash tables, but calling it a symbol table can make it clearer).
这就是事情变得有趣的地方:对象有自己的“符号表”(通常这些只是哈希表,但称其为符号表可以使其更清晰)。
Now, after your next statement, you have 3 things to consider: The global symbol table, <object val 1>
's symbol table, and the heap.
现在,在您的下一条语句之后,您需要考虑 3 件事:全局符号表、<object val 1>
的符号表和堆。
Run the following line:
运行以下行:
a['one'] = {}
And now things look like this:
现在事情看起来像这样:
Global Symbol Table:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
's Symbol Table
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
Heap:
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> | <---we created a new object on the heap
+----------+-----------------+
.
.
Now you ran the following code:
现在您运行了以下代码:
a = a['one'];
This should hopefully seem to be a trivial change. The result is:
希望这看起来是一个微不足道的变化。结果是:
Global Symbol Table:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
's Symbol Table
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
Heap:
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
.
.
Following the memory locations to the heap should hopefully make it clear why you got the output you did.
沿着内存位置到堆应该可以清楚地说明为什么你得到了你所做的输出。
Now things get even MORE interesting, because now you are doing:
现在事情变得更有趣了,因为现在你正在做:
a['two'] = 2;
Ok, so let's take this step by step.
好的,让我们一步一步来。
a
points to memory location0x400004
which contains<object val 2>
<object val 2>
is an empty object, thus its symbol table starts off empty- By running this line, we add the variable 'two' to
<object val 2>
's symbol table.
a
指向0x400004
包含的内存位置<object val 2>
<object val 2>
是一个空对象,因此它的符号表开始是空的- 通过运行这一行,我们将变量 'two' 添加到
<object val 2>
's 符号表中。
If you're not tired of looking at these diagrams yet, you will be. Things now look like this:
如果您还没有厌倦查看这些图表,那么您一定会厌倦的。事情现在看起来像这样:
Global Symbol Table:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
's Symbol Table
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
<object val 2>
's Symbol Table
<object val 2>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| two | 0x400008 |
+--------+-----------------+
Heap:
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
| 0x400008 | 2 (literal val) | <-- yes, even integers are stored on the heap
+----------+-----------------+ in JavaScript.
.
.
If you diligently take the time to follow the memory locations, you will see that your browser displayed the correct output.
如果您认真地花时间跟踪内存位置,您将看到您的浏览器显示了正确的输出。
回答by maerics
Think of the anonymous object as itself having a name:
把匿名对象想象成它自己有一个名字:
a = {}; // The variable "a" now points to (holds) an anonymous object.
b = a; // "b" points to the same anonymous object held by "a".
a = 123; // "a" now holds some other value.
b; // "b" still holds the anonymous object.
The key is to remember that variables hold references to objects, not references to other variables. And the same object may be referred to by any number of variables.
关键是要记住变量保存对对象的引用,而不是对其他变量的引用。并且同一个对象可以被任意数量的变量引用。
回答by Greg Hewgill
Objects in Javascript can exist by themselves without needing a name. For example:
Javascript 中的对象可以独立存在而无需名称。例如:
{}
is a new instance of a dictionary object.
是字典对象的新实例。
a = {};
creates a new dictionary object and makes a
refer to it. Now
创建一个新的字典对象并a
引用它。现在
b = a;
makes b
refer to the same underlying object. You can then make a
point somewhere else:
使b
引用相同的底层对象。然后你可以在a
其他地方指出:
a = "hi";
and b
still points to the same dictionary object it did before. The behaviour of b
is unrelated to how you change what a
points to.
并且b
仍然指向它之前所做的同一个字典对象。的行为b
与您如何更改a
指向的内容无关。
回答by R01010010
As far as i know you overwrited aso i guess the engine saves it in another memory space, whereas bstill pointing to the old a's memory address (which somehow doesn't get destroyed).
据我所知你覆盖了 a所以我猜引擎将它保存在另一个内存空间中,而b仍然指向旧的a的内存地址(不知何故不会被破坏)。