Javascript指针/引用的疯狂.有人能解释一下吗?
Javascript pointer/reference craziness. Can someone explain this?
Javascript通过引用传递对象。这很有道理。但是一旦你开始操作这些对象,一切都以一种看起来不直观的方式运行。我举个例子:
var a, b;
a = {}
b = a;
a['one'] = {};
console.log( JSON.stringify(a) );
// outputs: {"one":{}}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
这一切都很好,因为现在b
有一个指向a
的指针,所以预计将内容分配给a
也会影响b
。
但是如果我这样做:
a = a['one'];
console.log( JSON.stringify(a) );
// outputs: {}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
这让我很惊讶。我希望a
和b
仍然是相同的(并且是{}
,因为a['one']
之前被设置为{}
, a
被设置为a['one']
)。
但事实并非如此。当a
被赋值给新的对象时,它似乎失去了对b
的引用,但b
保持了a
在a
失去对b
的引用之前的值。
但是如果我这样做:
a['two'] = 2;
console.log( JSON.stringify(a) );
// outputs: {"two":2}
console.log( JSON.stringify(b) );
// outputs: {"one":{"two":2}}
什么?a
显然已经失去了对b
的引用,但b
似乎仍然有对a
的引用。
是否空对象{}
指向内存中的某个地方,所以每个引用它的变量现在都指向同一个地方?
能不能找个对这个有深刻理解的人给我解释一下?
逐行执行示例:
a = {}
a
现在引用新对象。
b = a;
b
现在引用a
引用的对象相同。注意,它没有引用a
。
a['one'] = {};
新对象现在有一个索引'one'
来引用另一个新对象。
当你这样做
a = a['one'];
您正在设置a
引用a['one']
,这是您在执行a['one'] = {}
时创建的新对象。b
仍然引用你用a = {}
创建的对象。
当你说"a
已经失去了对b
的引用"时,你混淆了这个问题,因为a
没有引用b
,反之亦然。a
和b
指代对象,也可以用来指代其他对象。这样的:
使用a = {}; b = a
,您得到
a
'
'
{ }
/
/
b
然后用a['one'] = {}
得到
a
'
'
{ one: { } }
/
/
b
然后用a = a['one']
得到
a - - - -
'
{ one: { } }
/
/
b
: p你正在深入到编织粗糙的细节中,我很高兴你问了,因为最后你会更明智。
不要从指针的角度看它,因为我认为这是你困惑的地方。可以从堆(或者只是"内存")和符号表的角度来考虑它。
让我们从代码的前几行开始:
var a, b;
a = {}
b = a;
这里所做的是在堆上创建一个对象,在符号表上创建两个符号。它看起来像这样:
符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
.
事情变得有趣了:对象有自己的"符号表"(通常这些只是散列表,但称其为符号表会更清楚)。
现在,在下一个语句之后,您有3件事情要考虑:全局符号表、<object val 1>
的符号表和堆。
运行以下行:
a['one'] = {}
现在是这样的:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> | <---we created a new object on the heap
+----------+-----------------+
.
现在运行以下代码:
a = a['one'];
这应该看起来是一个微不足道的改变。结果是:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
.
跟随内存位置到堆应该能够清楚地说明为什么你得到了你所做的输出。
现在事情变得更有趣了,因为现在你在做:
a['two'] = 2;
让我们一步一步来。
-
a
指向包含<object val 2>
的内存位置0x400004
-
<object val 2>
是一个空对象,因此它的符号表从空 开始通过运行这一行,我们将变量'two'添加到
<object val 2>
的符号表中。如果你还不厌倦看这些图表,你会厌倦的。现在看起来像这样:
全局符号表:
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
<object val 2>
的符号表
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| two | 0x400008 |
+--------+-----------------+
堆:
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
| 0x400008 | 2 (literal val) | <-- yes, even integers are stored on the heap
+----------+-----------------+ in JavaScript.
.
如果您认真地花时间跟踪内存位置,您将看到浏览器显示了正确的输出。
认为匿名对象本身有一个名称:
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.
关键是要记住变量保存对对象的引用,而不是对其他变量的引用。并且同一个对象可以被任意数量的变量引用。
Javascript中的对象可以自己存在而不需要名称。例如:
{}
是一个字典对象的新实例。
a = {};
创建一个新的字典对象,并使a
引用它。现在
b = a;
使b
引用相同的底层对象。然后你可以让a
指向其他地方:
a = "hi";
和b
仍然指向它之前所指向的同一个字典对象。b
的行为与您如何更改a
指向无关。
据我所知,您覆盖了a所以我猜引擎将其保存在另一个内存空间中,而b仍然指向旧的a的内存地址(以某种方式不被破坏)。
- 你能解释一下这个阶乘函数是如何工作的吗?
- 你能解释一下为什么这个javascript不正确吗
- 有人能解释一下evaluate()和dragAndDrop()在下面的角度测试代码中调用了什么吗
- 你能解释一下下面的javascript吗?
- 有人能解释一下;r'的对象在下面的代码示例中执行
- 谁能解释一下这句话的意思吗;var upload_file_count_text=+filenames.length++
- 有人能解释一下如何#ifeq吗/section键使用handle.js工作
- 你能解释一下第 3 章 Eloquent js 中的这个递归解决方案吗?
- 你能解释一下 javascript 中的返回吗?
- 你能解释一下这种奇怪的函数声明行为吗?
- 用“i”替换字符串中的元音..你能解释一下这个表达吗?someText.replace(/[aAeEoOuU]/ig,“
- 你能解释一下jQuery如何同时使用$作为函数和对象吗?
- 你能解释一下ngList指令吗?
- 你能解释一下这个JavaScript语法(变量外推)吗?
- 谁能解释一下这个 ajax .each 函数中的项目来自哪里
- 今天有人能解释一下吗.getDate()>25?5:(today.getDate()>16?25:15)
- 有人能解释一下这个require.js示例中涉及的语法吗
- 有人能解释一下这个JavaScript代码吗
- 有人能解释一下这个递归JS代码来计算指数吗
- 有人能解释一下下面的javascript RE代码吗