你将知道:
- “传递” 值是什么意思
- 什么是按值传递
- 传递物品
- JavaScript 中没有传递引用!
介绍
当需要在 JavaScript 中分配或简单地将一个值传递给其他标识符时,我们就会看到通常所说的 按值传递 。
严格来说,JavaScript 中传递值的方式只有一种,那就是复制值,这本质上就是所谓的“按值传递”。换句话说,JavaScript 实际上只支持“按值传递” 。
然而在 JavaScript 中,绝对没有办法通过引用传递数据(至少目前是这样)。
‘传递’ 是什么意思?
基本上,每当我们在 JavaScript 中将一个标识符(即变量、常量、属性等)分配给另一个标识符时,我们所做的事情就是传递标识符。传递标识符只是将其分配给另一个标识符。
例如,如果我们有一个变量 x
并将其分配给另一个变量 y
,我们会说我们将变量 x
传递给 y
。类似地,如果我们将变量 x
作为参数提供给函数 f()
,我们再次说我们正在传递变量 x
但这次是传递给函数 f()
。
什么是按值传递?
按值传递是指通过复制其值来传递标识符。
在按值传递中,传递的标识符中存储的值被复制 ,然后其副本存储在另一个标识符中。
因此,我们说 “按值传递” ,也就是说,我们传递存储的精确值。
var text = 'Hello';
var str = text;
text = 'Bye';
console.log(str);
那么,代码将记录值 'Hello'
首先,我们定义一个变量 text
,并将其初始化为 'Hello'
。然后,我们将 text
赋值给第二个变量 str
。完成后,我们最终修改 text
,然后输出 str
值。
现在,人们可能会认为,既然 text
已赋值给 str
,那么更改 text
也会导致 str
发生更改;但这并没有发生。这仅仅是因为 JavaScript 中的原语是按值传递的。
当我们将 text
分配给 str
时,将复制存储在 text
中的实际值 (即 'Hello'
,并将副本分配给 str
。
换句话说,变量 text
和 str
都有各自独立的 'Hello'
值;改变其中一个不会明显改变另一个。
上面的代码从技术上讲等同于下面的代码:
var str = 'Hello'; // own value
var text = 'Hello'; // own value
text = 'Bye';
console.log(str);
JavaScript 数据类型不只有原始类型,对吧?我们还有对象。现在,对象传递也是按值传递的。
ha?
在 JavaScript 中,对象通过其引用 存储在标识符中, 而不是通过其实际值。
引用可以被认为是指向存储对象位置的内存地址。
由于 JavaScript 中的对象通过其引用存储在标识符内,因此当传递该对象时,实际传递的是该引用。
对象是真实的数据;引用是对象在程序中的表示方式。
再次强调,需要特别注意的是,对象仍然像 JavaScript 中的原语一样传递,即按值传递;对象唯一的不同之处在于它们的存储方式,即通过引用。
var obj = { x: 10 };
var obj2 = obj;
obj.x = 20;
console.log(obj2.x); // 20
我们首先定义一个变量 obj
,其值为 { x: 10 }
然后定义另一个变量 obj2
,并将其初始化为 obj
。
接下来,我们改变 obj
的属性 x
,然后记录 obj2
的相同属性。
obj.x
在 obj2
中可见,仅仅是因为 obj
和 obj2
都引用内存中 obj
同一个对象 。obj 和 obj2
不保存单独的对象 - 它们保存完全相同的对象。
JavaScript 中对象是如何存储的
这是我们的 obj
变量。它包含一个指向内存中对象 { x: 10 }
的值(箭头所示)。这个值就是我们所说的引用。
当我们将 obj
赋值给另一个变量 obj2
时,会发生以下情况:
在 JavaScript 中将对象分配给另一个标识符
obj
中存储的值(引用)仅仅被复制到 obj2
中。因此, obj2
指向(箭头所示) obj
指向的同一个对象 { x: 10 }
。
如果我们现在继续更改 obj
的属性,就像我们在上面的代码中通过更新属性 x
所做的那样,那么该更改在 obj2
中也会可见。
重申一下:
当我们将 obj
分配给 obj2
时, obj
中存储的实际值 (即引用 )被复制,并将该副本分配给 obj2
。 实际也还是值传递,只是这个值是引用。
从今以后,如果我们改变存储在 obj
(或 obj2
)中的对象,这些变化显然也会在 obj2
(或 obj
)中可见,因为它们都包含完全相同的对象。
(牢记上面的图)
JavaScript 中没有传递引用!
你不能真正在 JavaScript 中通过其引用(在内存中)传递标识符,并期望其他代码能够控制该标识符中存储的内容。
事实上,很容易确认传统意义上的 JavaScript 不支持传递引用。
以上面部分的代码为例,如果我们将任何值重新分配给 obj
或 obj2
本身,另一个变量不会发生神奇的变化。
var obj = { x: 10 };
var obj2 = obj; // This is just pass-by-value.
obj = 20;
console.log(obj2);
{ x: 10 }
这里的一切与之前相同,只是现在变量 obj
自身发生了改变(而不是像之前那样改变其属性 x
)。然后,直接输出 obj
,而不是输出 obj.x
。
因为 JavaScript 中没有真正意义上的按引用传递,所以我们在为 obj
分配值时, obj2
不会改变 - 它会继续保留 { x: 10 }
。
这纯粹是因为没有任何东西将两个变量 obj
和 obj2
联系在一起。
简单来说就是,本来他俩的值都是引用,比如 16 位一个引用地址,指向了内存中的{x: 10},所以,当 xxx.x 的时候,才会影响这两个对象,但实际他俩是两个变量,当 obj = 20 的时候, 那就是一个原语,最基础的值 20。那么得到的结果当然就是 obj = 20 , obj2 = {x:10}