传值 (Pass by value)
在 JavaScript 中,当变量的值是原生类型时,就是传值
如果传递的变量是原生类型时,传递的就会是值的副本,而不是传递变量的内存位置。我们可以使用 =
来赋予变量一个值举以下的例子,分别赋予不同数字给 a
、b
:
const a = 1;const b = a + 1;
可以注意到第 2 行,将 b
指定为 a
的值 +1,这时候 c
的值就会是 1 + 1 = 2
,非常直觉也很好理解,这就是所谓的「传值(Pass by value)」
传址 (Pass by reference)
在 JavaScript 中,当变量不是原生类型时,就是传址
当变量是对象或数组的情况下,JavaScript 会需要额外的记录代表其内存位置,因此变量内储存的并不是实际的内容,而是一个内容所在的内存位置。举以下图表为例,图表中的 b
变量实际上持存的是内存地址:
const a = 1;const b = [1, 2];
变量 | 值 |
---|---|
a | 1 |
b | 0x01 |
内存地址 | 值 |
---|---|
0x01 | [1,2] |
了解了传址的概念后,我们来延伸前面的例子,如果这时候有个变量 c = b
那么画成图表就会是这样:
const a = 1;const b = [1, 2];const c = b;
变量 | 值 |
---|---|
a | 1 |
b | 0x01 |
c | 0x01 |
内存地址 | 值 |
---|---|
0x01 | [1,2] |
如此一来 b
与 c
所指向的内存位置都是 0x01
,因此当我们对 c
做修改时,b
也会跟着改变:
let a = 1;let b = [1, 2];let c = b;b.push(3);// 结果:b 与 c 都变成 [ 1, 2, 3 ] 了!
这也是为什么 b
与 c
的值都会变成 [1, 2, 3]
,因为 b
与 c
都指向了同一个内存位置。
相等但不相等
了解前面传值与传址的差异后,会发现内存位置与值是全然不同的东西,一个是指针,一个是内容,实际就像以下图表范例。
const a = [1, 2];const b = [1, 2];
console.log(a === b); // false
变量 | 值 |
---|---|
a | 0x01 |
b | 0x02 |
内存地址 | 值 |
---|---|
0x01 | [1,2] |
0x02 | [1,2] |
let a = [1, 2];let b = a;console.log(a === b); // true
变量 | 值 |
---|---|
a | 0x01 |
b | 0x01 |
内存地址 | 值 |
---|---|
0x01 | [1,2] |
总结
了解 JavaScript 是如何存储变量有助于更好的操控数据,避免出现改 A 却动到 B 的状况。