JavaScript Pass by Value and Reference, The Difference?
JavaScript 传值与传址,都几咧?
传值 (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 的状况。