重新分配,变异,引用类型和值类型

时间:2016-03-18 23:11:42

标签: javascript variables reference immutability key-value

您如何恰当地解释为什么这两个例子不同?​​

// Reassignment
let a = 1;
let b = a;
a = 2;
console.log(b); // → 1

// Mutation
let myArray = [1, 2, 3];
let ourArray = myArray;
ourArray[2] = 10;
console.log(myArray); // → [1, 2, 10]

关于变量标签在两者之间表现不同的原因,许多资源声称它是由于参考类型和值类型之间的差异而引起的。但是,这不仅仅适用于之间的差异吗?

当明确地谈论变量标签时(即为什么第一个例子中的标签不跟踪值的变化,而在第二个例子中它是如此),并不是真正的差异与突变与重新分配

毕竟,我们可以轻松地重新分配myArray或ourArray,它们都不会有任何类型的持续链接。并且,如果原始值在JavaScript中理论上是可变的,那么可以使第一个示例与第二个示例一样。

后续问题

我还读过关于原始值是否仅在内存中存在一次的冲突信息。例如,如果第一个在内存中只存在一次,则将变量标签可视化为名称标签是合适的,每个引用第一个的名称标签都会被卡住。对于同一个,对吗?

同样,如果第一个能够被改变,那么每个名称标签将跟踪对该第一个的相同改变。但由于其中一个是不可变的,因此名称标记可以继续引用相同的数字,也可以将它们取下并粘贴到不同的值(重新分配)。

我在这里走在正确的轨道上吗?

2 个答案:

答案 0 :(得分:1)

您将实施细节("在内存中存在一次")与评估策略("参考类型和值类型")和特定表达("变异与重新分配和##)混合在一起34;)在你的问题中。各种浏览器的实施细节各不相同,将来可能会发生变化。

Javascript中有两种评估策略:

  • 按值复制(调用函数时按值传递)
  • 按引用复制(调用函数时按引用传递)

价值类型

值类型始终按值复制。假设字符串在Javascript中是可变的:

let s = "abc";
let t = s;

s[0] = "x";
s; // "xbc";
t; // "abc";

基于值类型的变量(或标识符或名称绑定)直接包含其值。如果这样的可变字符串发生变异,那么只会影响相应标识符的值。

与字符串不同,数字是原子的。对于原子基元,突变和重新分配没有实际区别:

let n = 0;
n = 1, n++, n = n + 1; // all reassignments

参考类型

包含引用类型的变量仅包含对此类型的引用,这是Javascript中的复杂值(对象)。如果两个变量引用同一个对象,它们每个都包含此引用的副本,而不是直接别名。因此,如果重新分配两个变量中的一个,这不会影响另一个。

引用类型具有标识,即它们的标识不再与值绑定:

let xs = [1];
xs === [1]; // false

答案 1 :(得分:1)

  

当明确谈论变量标签时,真正的区别与变异与重新分配有关吗?

不确定。我假设你的意思是一个变异对象和分配变量。但你无法像那样区分它们。我还可以说我分配给对象属性(在你的第二个例子中)或变异"变量标记"记忆细胞(在你的第一个例子中)。真的有区别吗?

但实际上,无论变量(标签,存储单元,寄存器)是否包含原始值或参考值,变量(标签,存储单元,寄存器)的作用始终相同。

  

我一直在阅读关于原始值是否只在内存中存在一次的冲突信息。

嗯,关键是它并不重要因为原始值(根据定义)是不可变的。 JS实现可以复制它们,或者共享引用,脚本无法区分这种行为。

在现实世界中,数字和布尔值通常被复制,而字符串通常是interned(共享)。