在 JavaScript 中,变量(和属性)包含values。值可以有许多不同的类型(数字、字符串、布尔值),其中之一是对象引用,这是一个参考一个对象,但不是实际的对象本身。理解对象引用的一个简单方法是,它只是一个数字,就像一个非常大的数组的索引,告诉我们对象在哪里。 (这并不完全正确,但这是一种有用的思考方式。)或者用非编程术语来说,乔可能有一张写着“123 Any St.”的纸。上面写着,那就是乔的家。论文是一个变量(或属性); “123 任何圣”是一个值(在本例中是一个对象引用),而房子是一个对象。
对象不是值,因此它们不能存储在变量或属性中(或作为函数参数传递)。仅有的参考对他们来说可以。
当您为变量或属性赋值(或将其作为参数传递到函数中)时,您copying从源头传入它的值。所以a = b
copies的值来自b
into a
. When b
包含一个对象引用,被复制的是引用,而不是对象;然后a
and b
两者都引用同一个对象。就像玛丽拿出一张纸(a
)并抄下乔的纸上的内容(b
)。现在两张纸上都写着乔的房子在哪里。这house没有被复制,只是告诉我们它在哪里的信息。
考虑到这一点,让我们看看您的代码。当你这样做时
window.gamelogic = {};
它创建一个对象并将其引用(值)复制到属性中gamelogic
。这是此时内存中内容的粗略草图,省略了lot不必要的细节:
+-------------------+
| (stuff omitted) | +-----------+
window:ref429--->| gamelogic: ref758 |------>| |
+-------------------+ +-----------+
然后你这样做:
var g = gamelogic;
which (挥手)创建一个变量(稍后我将解释挥手的情况)并分配(复制)value in gamelogic
到它。由于该值是对象引用,g
and gamelogic
现在指向同一个地方;也就是说,他们refer对于同一个对象:
+-------------------+
| (stuff omitted) |
window:ref429--->| gamelogic: ref758 |---+
+-------------------+ | +-----------+
+-->| |
| +-----------+
g: ref758--------------------------------+
然后你就做
g.points = 1;
它在该对象上创建一个名为points
并复制该值1
进去:
+-------------------+
| (stuff omitted) |
window:ref429--->| gamelogic: ref758 |---+
+-------------------+ | +-----------+
+-->| points: 1 |
| +-----------+
g: ref758--------------------------------+
让我们强调一下我们在这里所做的事情:我们没有改变g
无论如何,它仍然是一样的:对对象的引用gamelogic
也参考。我们所做的是改变了状态该对象的(通过向其添加属性)。这是对象的关键之一:它们具有可以更改的状态。当该状态发生更改时,当您查看它时,拥有哪个引用副本并不重要;重要的是。无论如何,您都会看到相同的对象及其(更新的)状态。
好的,继续:
g.array = ["foo","bar"];
它创建一个数组(它是一个对象),并创建一个名为的属性array
在我们的对象上,并将数组引用的值复制到属性中:
+-------------------+
| (stuff omitted) |
window:ref429--->| gamelogic: ref758 |---+
+-------------------+ | +---------------+ +----------+
+-->| points: 1 | | 0: "foo" |
| | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+ +---------------+ +----------+
然后你就可以:
var b = g.points;
which (挥手)创建一个变量并复制其中的值g.points
(1
) 进去:
+-------------------+
| (stuff omitted) |
window:ref429--->| gamelogic: ref758 |---+
+-------------------+ | +---------------+ +----------+
+-->| points: 1 | | 0: "foo" |
| | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+ +---------------+ +----------+
b: 1
Then
b = b + 1;
得到值1
from b
, adds 1
到它,并存储新值(2
) in b
. g.points
完全不受影响:
+-------------------+
| (stuff omitted) |
window:ref429--->| gamelogic: ref758 |---+
+-------------------+ | +---------------+ +----------+
+-->| points: 1 | | 0: "foo" |
| | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+ +---------------+ +----------+
b: 2
以上要点是:
- 变量和属性(以及函数参数)包含values.
- A values具有类型,例如字符串、数字、布尔值或对象引用.
- An 对象引用只是一个表示对象所在位置的值。
- 对象不是值;参考对象就是值。
- 对象具有可以更改的状态。*
(* 如果他们允许的话。可以创建一个不允许其状态改变的对象;这些对象被称为“不可变”对象。并且它可以非常非常方便和强大地做到这一点。在 JavaScript 中,你这样做Object.freeze http://ecma-international.org/ecma-262/5.1/#sec-15.2.3.9类似,因为默认情况下对象非常松散,您只需通过分配即可向它们添加属性。在许多其他语言中,它更基本:您只是不定义任何可以更改的公共字段,并且不定义任何更改对象状态的公共方法。)
关于“创建变量”挥手,我忽略了其中的两个细节,因为它们当时并不重要:
在 JavaScript 中,var
声明是在代码开始运行之前处理的,因此变量g
and b
两者都在您的分步代码的第一行运行之前就已经创建了。最初, 的值是undefined
在他们中。
因为你用过var
在全球范围内,b
and g
成为全局对象的属性,这就是window
指着。实际上,window
本身是全局对象的属性。在 ES5 之前,所有全局变量都是全局对象的属性。 (在 ES6/ES2015 中,我们有一个新的全局变量类别:let
, const
, or class
.)
因此从技术上讲,我们的第一个图表应该如下所示:
+--------------------------+
| +-------------------+ |
| | (stuff omitted) | |
+-->| window: ref429 |--+ +-----------+
| gamelogic: ref758 |------>| |
| g: undefined | +-----------+
| b: undefined |
+-------------------+
……但是,好吧,这似乎没什么用处。 :-)