传值(Pass by Value)
在 JavaScript 中,当变量的值是原生类型时,就是传值
如果传递的变量是原生类型时,传递的就会是值的副本,而不是传递变量的内存位置。我们可以使用 = 来赋予变量一个值举以下的例子,分别赋予不同数字给 a、b:
const a = 1;
const b = a + 1;
可以注意到第 2 行,将 b 指定为 a 的值 +1,这时候 c 的值就会是 1 + 1 = 2,非常直观也很好理解,这就是所谓的「传值(Pass by value)」
原生类型具体来说有:String、Number、Boolean、Undefined、Null,这些类型的数据是以「值」的方式来传递。
传址 (Pass by reference)
在 JavaScript 中,当变量不是原生类型时,就是传址。
当变量是对象或数组的情况下,JavaScript 会需要额外的记录代表其内存位置,因此变量内存储的并不是实际的内容,而是一个内容所在的内存位置。举以下图表为例,图表中的 b 变量实际上持存的是内存位址:
const a = 1;
const b = [1, 2];
变量 | 值 | 内存位址 | 值 |
---|---|---|---|
a | 1 | A | |
b | [1, 2] | B | A |
了解了传址的概念后,我们来延伸前面的例子,如果这时候有个变量 c = b 那么画成图表就会是这样:
const a = 1;
const b = [1, 2];
const c = b;
变量 | 值 | 内存位址 | 值 |
---|---|---|---|
a | 1 | A | |
b | [1,2] | B | A |
c | [1,2] | C | A |
如此一来 b 与 c 所指向的内存位置都是 A,因此当我们对 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 | [1,2] | A |
b | [1,2] | A |
let a = [1, 2];
let b = a;
console.log(a === b); // true - 内存地址一致
变量 | 值 | 内存位址 |
---|---|---|
a | [1,2] | A |
b | A |
总结
了解 JavaScript 是如何储存变量有助于更好的操控数据,避免出现改 A 却动到 B 的状况。