什么是不可改变的意思?

时间:2010-07-08 01:54:27

标签: javascript variables immutability

如果字符串是不可变的,那是否意味着.... (让我们假设JavaScript)

var str = 'foo';

alert(str.substr(1)); // oo

alert(str); // foo

这是否意味着,当在字符串上调用方法时,它将返回修改后的字符串,但它不会更改初始字符串?

如果字符串是可变的,这是否意味着第二个alert()也会返回oo

9 个答案:

答案 0 :(得分:103)

这意味着一旦实例化对象,就无法更改其属性。在你的第一个警报中,你不会改变foo。你正在创建一个新的字符串。这就是为什么在你的第二个警报中它会显示“foo”而不是oo。

  

在调用方法时是否意味着   一个字符串,它将返回修改后的   字符串,但它不会改变   初始字符串?

是。创建字符串后,没有任何内容可以更改。现在,这并不意味着您无法将新的字符串对象分配给str变量。您无法更改str引用的当前对象。

  

如果字符串是可变的,那就是   意味着第二个警报()将返回oo   还有吗?

从技术上讲,不,因为substring方法返回一个新字符串。使对象变为可变,不会改变方法。使其变为可变意味着从技术上讲,您可以使子串会改变原始字符串而不是创建新字符串。

答案 1 :(得分:93)

在较低级别,不变性意味着不会修改存储字符串的内存。创建字符串"foo"后,会分配一些内存来存储值"foo"。这个记忆不会改变。如果使用substr(1)修改字符串,则会创建一个新字符串,并分配一个将存储"oo"的内存的不同部分。现在内存中有两个字符串,"foo""oo"。即使你不再使用"foo",它也会一直存在,直到收集垃圾为止。

字符串操作相对昂贵的一个原因。

答案 2 :(得分:13)

不可变意味着无法更改或修改。

因此,当您为字符串赋值时,此值是从头开始创建的,而不是被替换。因此,每次为同一字符串分配新值时,都会创建一个副本。所以实际上,你永远不会改变原来的价值。

答案 3 :(得分:9)

我不确定JavaScript,但在Java中,字符串通过“字符串常量池”为不可变性带来了额外的一步。可以使用字符串文字("foo")或String类构造函数构造字符串。使用字符串文字构造的字符串是字符串常量池的一部分,相同的字符串文字将始终与池中的内存地址相同。

示例:

    String lit1 = "foo";
    String lit2 = "foo";
    String cons = new String("foo");

    System.out.println(lit1 == lit2);      // true
    System.out.println(lit1 == cons);      // false

    System.out.println(lit1.equals(cons)); // true

在上文中,lit1lit2都是使用相同的字符串文字构造的,因此它们指向相同的内存地址; lit1 == lit2会产生true,因为它们是完全相同的对象。

但是,cons是使用类构造函数构造的。虽然参数是相同的字符串常量,但构造函数为cons分配了新内存,这意味着conslit1lit2不是同一个对象,尽管包含相同的数据

当然,由于这三个字符串都包含相同的字符数据,因此使用equals方法将返回true。

(两种类型的字符串结构当然都是不可变的)

答案 4 :(得分:3)

不可变意味着价值无法改变。一旦创建了一个字符串对象就不能被修改为其不可变的。如果您请求字符串的子字符串,则会创建一个包含所请求部分的新String。

在操作字符串时使用StringBuffer会使操作更有效率,因为StringBuffer将字符串存储在带有变量的字符数组中,以保存字符数组的容量和数组的长度(以字符数组形式表示的字符串)

答案 5 :(得分:3)

可变性的教科书定义有责任或可能会有变更或更改。 在编程中,我们使用这个词来表示允许状态随时间变化的对象。不可变的值恰恰相反 - 在创建之后,它永远不会改变。

如果这看起来很奇怪,请允许我提醒您,我们一直使用的许多值实际上都是不可变的。

var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

我认为没有人会惊讶地发现第二行绝不会改变语句中的字符串。 实际上,没有字符串方法可以更改它们操作的字符串,它们都返回新的字符串。原因是字符串是不可变的 - 它们不能改变,我们只能创建新的字符串。

字符串不是JavaScript中内置的唯一不可变值。数字也是不可改变的。你能想象一个评估表达式2 + 3会改变数字2意义的环境吗?这听起来很荒谬,但我们一直用我们的对象和数组来做这件事。

答案 6 :(得分:2)

从字符串到堆栈...从Eric Lippert's blog获取的简单易懂的示例:

Path Finding Using A* in C# 3.0, Part Two ...

  

像System.Collections.Generic.Stack这样的可变堆栈   显然不适合。我们想成为   能够采取现有的路径和   为它创造新的路径   最后一个元素的邻居,   但推动一个新节点   标准堆栈修改堆栈。   我们必须复制堆栈   在推它之前,这是愚蠢的   因为那时我们会重复所有   其内容不必要。

     

不可变堆栈没有此问题。推动不变的   堆栈只是创建一个全新的堆栈   链接到旧的   尾巴。由于堆栈是不可变的,   没有其他代码的危险   来了,弄乱了尾巴   内容。你可以继续使用   老堆栈到你心里的内容。

要深入了解不可变性,请阅读Eric的帖子,从这一篇开始:

Immutability in C# Part One: Kinds of Immutability

答案 7 :(得分:0)

掌握这个概念的一种方法是查看javascript如何处理所有对象,这是通过引用。这意味着在实例化之后所有对象都是可变,这意味着您可以添加具有新方法和属性的对象。这很重要,因为如果您希望对象是不可变的,则对象在实例化后不能更改。

答案 8 :(得分:0)

尝试:

let string = "name";

string[0] = "N";

console.log(string); // name not Name

string = "Name";

console.log(string); // Name

因此,这意味着字符串是不可变的,但不是恒定的,用简单的话来说,可以进行重新分配,但不能更改某些部分。