理解 Javascript 不可变变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16115512/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 03:19:35  来源:igfitidea点击:

Understanding Javascript immutable variable

javascript

提问by Antonis Grigoriadis

I am trying to understand what a Javascript immutable variable means. If I can do:

我试图了解 Javascript 不可变变量的含义。如果我能做到:

var x = "astring";
x = "str";
console.log(x); //logs str` , then why it is immutable?

The only answer I can think (from the little bit of C I know) is that var x is a pointer to a memory block with the value "astring", and after the 2nd statement it points to another block with the value "str". Is that the case?

我能想到的唯一答案(从 CI 的一点点知道)是 var x 是一个指向值为“astring”的内存块的指针,在第二条语句之后它指向另一个值为“str”的块。是这样吗?

And a bonus question: I was confused by the value types of Javascript. Are all variables objects under the hood? Even number and strings?

还有一个额外的问题:我对 Javascript 的值类型感到困惑。引擎盖下的所有变量都是对象吗?偶数和字符串?

回答by GitaarLAB

Valuesare immutable; variablesare not; they hold a reference to their (primitive) values.

是不可变的;变量不是;它们持有对其(原始)值的引用。

The three primitive types string, number and booleanhave corresponding types whose instances are objects: String, Number, Boolean.
They are sometimes called wrapper types.

三个基本类型string、number 和 boolean具有对应的类型,其实例是对象:String、Number、Boolean
它们有时被称为包装器类型

The following values are primitive:

以下值是原始值:

  • Strings: "hello"
  • Numbers: 6, 3.14 (all numbers in JavaScript are floating point)
  • Booleans: true, false
  • null: usually explicitly assigned
  • undefined: usually the default (automatically assigned) value
  • 字符串:“你好”
  • 数字:6、3.14(JavaScript 中的所有数字都是浮点数)
  • 布尔值:真、假
  • null:通常显式分配
  • 未定义:通常是默认(自动分配的)值

All other values are objects, including wrappers for primitives.

所有其他值都是对象,包括原语的包装器。

So:

所以:

  • Objects are mutable by default
  • Objects have unique identities and are compared by reference
  • Variables hold references to objects
  • Primitives are immutable
  • Primitives are compared by value, they don't have individual identities
  • 对象默认是可变的
  • 对象具有唯一标识并通过引用进行比较
  • 变量保存对对象的引用
  • 原语是不可变的
  • 基元是按值比较的,它们没有个体身份

You might find The Secret Life of JavaScript Primitivesa good explanation.

您可能会发现The Secret Life of JavaScript Primitives是一个很好的解释。

Also, in ES6 there is a new constkeyword, that creates a read-only named constant that cannot change value through assignment or be re-declared while the script is running.

此外,在 ES6 中有一个新的const关键字,它创建一个只读的命名常量,该常量不能通过赋值更改值或在脚本运行时重新声明。

Hope this helps!

希望这可以帮助!

回答by aMother

First, in C "A string is an array of characters with last elem = '\0' ". They are mutable.
If you declare and initialize a string in C like this:

首先,在 C 中“一个字符串是一个字符数组,最后一个 elem = '\0'”。它们是可变的。
如果像这样在 C 中声明并初始化一个字符串:

char str[] = "Foo";

What you are basically doing is reserving 4 bytes ( probably 8bit-byte, don't mind this probably if it hurts you ). The word str serves as a pointer to the first elem of this array. So, if you do like this:

您基本上要做的是保留 4 个字节(可能是 8 位字节,如果它伤害了您,请不要介意)。单词 str 用作指向该数组第一个元素的指针。所以,如果你这样做:

str[0] or *(str) = 'G'

then it will mutate the value at that address instead of creating new array. You can verify it by printing out the address of str. In both cases it will be same.

然后它将改变该地址处的值而不是创建新数组。您可以通过打印出 str 的地址来验证它。在这两种情况下,它将是相同的。

Now in case of JavaScript string is a primitive type. All operations on string are done by value instead of by reference. So, doing this will produce true.

现在在 JavaScript 字符串是原始类型的情况下。对字符串的所有操作都是按值而不是按引用完成的。所以,这样做会产生真。

var str1 = "foo";
var str2 = "foo";
str1 === str2; => true

The initialization of string asks for a buffer to fit "foo" and binds the name str1 to it. What makes them immutable is that you can't change that buffer. So, you can't do this:

string 的初始化要求一个缓冲区以适合“foo”并将名称 str1 绑定到它。使它们不可变的原因是您无法更改该缓冲区。所以,你不能这样做:

str1[0] = 'G'

Executing this command will produce no warning or error in non-strict mode but, it will not change the str1. You can verify it by

在非严格模式下,执行此命令不会产生警告或错误,但不会更改 str1。您可以通过以下方式验证

console.log(str1) => "foo"

But if you do like this:

但如果你这样做:

str1 = "goo"

what you are actually doing is that you are asking for a new buffer to fit "goo" and bind identifier str1 to it. No change in that old buffer containing "foo".

您实际上在做的是要求一个新的缓冲区来适应“goo”并将标识符 str1 绑定到它。包含“foo”的旧缓冲区没有变化。

So, what happens to "foo"?

那么,“foo”会发生什么?

Java Script has an automatic garbage collector. When it sees some chunk of memory that no longer can be referenced by any identifier or ... then it consider that memory free.

Java Script 有一个自动垃圾收集器。当它看到一些不再可以被任何标识符引用的内存块时,或者......然后它认为该内存是空闲的。

Same happens to number,booleans. Now, about wrapper objects! Whenever you try to access a property on string like this:

数字,布尔值也是如此。现在,关于包装对象!每当您尝试像这样访问字符串上的属性时:

str1.length;

What JavaScript does it creates a new object using String class and invoke the methods on string. As soon as the function call returns, the object is destroyed. The below code explains it further:

JavaScript 做什么它使用 String 类创建一个新对象并调用字符串上的方法。一旦函数调用返回,对象就会被销毁。下面的代码进一步解释了它:

var str = "nature"; 
str.does = "nurtures"; //defining a new property; 
console.log(str.does) => undefined

because the object has been destroyed. Try this!

因为对象已经被销毁了。试试这个!

var str = new String("Nature");
str.does = "nurtures";
console.log(str) =>  ??

this str is really an object...

这个 str 真的是一个对象......

Conclusion: In C , in a single scope the variable name serves as a pointer. So, int, float, string all are mutable. But in Java Script a primitive type variable name serves as value not as reference

结论:在 C 中,在单个作用域中,变量名用作指针。所以,int、float、string 都是可变的。但是在 Java Script 中,原始类型变量名称用作值而不是引用

References: C++ primer plus, Java Script The Definitive Guide, C by Stephen Kochan

参考资料:C++ 入门加版,Java Script The Definitive Guide,C by Stephen Kochan

回答by CBass

You are correct. Strings (and numbers) are immutable in java script (and many other languages). The variables are references to them. When you "change the value of a variable" you are changing the string (or whatever) that the variable references, not the value itself.

你是对的。字符串(和数字)在 java 脚本(和许多其他语言)中是不可变的。变量是对它们的引用。当您“更改变量的值”时,您正在更改变量引用的字符串(或其他任何内容),而不是值本身。

回答by webAfrique

I think many new programmers believe immutability to mean that primitive values cannot be changed by reassignment.

我认为许多新程序员认为不变性意味着原始值不能通过重新分配来改变。

var str = "testing";
var str = "testing,testing";
console.log(str); // testing, testing

var fruits = ["apple", "banana", "orange"];

fruits[0] = "mango";

console.log(fruits); //["mango", "banana", "orange"]

The values associated with both mutable and immutable types can be changed through reassignment as the above examples with strings and arrays show. But then, these data types have associated functions(methods) that are used to manipulate the values belonging to each data type. This is where mutability/immutability is seen. Since arrays are mutable, any manipulation by an array method affects the array directly. For example,

与可变和不可变类型关联的值可以通过重新分配来更改,如上述字符串和数组示例所示。但是,这些数据类型具有关联的函数(方法),用于操作属于每种数据类型的值。这是可变性/不变性被看到的地方。由于数组是可变的,因此数组方法的任何操作都会直接影响数组。例如,

var fruits = ["mango","banana", "orange"];
fruits.pop(); 
console.log(fruits) //["mango", "banana"]


The array.pop() method deleted "orange" from the original fruits array.
But with strings for example,


var name = "Donald Trump";
name.replace("Donald", "President");
console.log(name)//Donald Trump

the original string remains intact!

Immutability disallowed any altering of the original string by the string method. Instead, the method produces a new string if the method operation is assigned to a variable like so:

不变性不允许通过字符串方法对原始字符串进行任何更改。相反,如果将方法操作分配给变量,则该方法会生成一个新字符串,如下所示:

var name = "Donald Trump";
var newName = name.replace("Donald", "President");
console.log(newName);//President Trump