简体   繁体   English

理解 Javascript 不可变变量

[英]Understanding Javascript immutable variable

I am trying to understand what a Javascript immutable variable means.我试图了解 Javascript 不可变变量的含义。 If I can do:如果我能做到:

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 CI 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".我能想到的唯一答案(从 CI 的一点点知道)是 var x 是指向值为“astring”的内存块的指针,在第二条语句之后,它指向另一个值为“str”的块。 Is that the case?是这样吗?

And a bonus question: I was confused by the value types of Javascript.还有一个额外的问题:我对 Javascript 的值类型感到困惑。 Are all variables objects under the hood?引擎盖下的所有变量都是对象吗? Even number and strings?偶数和字符串?

Values are immutable; 是不可变的; variables are not; 变量不是; they hold a reference to their (primitive) values. 他们拥有对其(原始)值的引用。

The three primitive types string, number and boolean have corresponding types whose instances are objects: String, Number, Boolean . 字符串,数字和布尔值这三种原始类型具有对应的类型,其实例是对象: 字符串,数字,布尔值
They are sometimes called wrapper types . 它们有时称为包装器类型

The following values are primitive : 以下是原始值:

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

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 Primitives a good explanation. 您可能会发现JavaScript原语的秘密生活是一个很好的解释。

Also, in ES6 there is a new const keyword, 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! 希望这可以帮助!

First, in C "A string is an array of characters with last elem = '\\0' ". 首先,在C中,“字符串是最后一个elem ='\\ 0'的字符数组”。 They are mutable. 它们是可变的。
If you declare and initialize a string in C like this: 如果像这样在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 ). 您基本上要做的是保留4个字节(可能是8位字节,如果这对您造成伤害,请不要介意)。 The word str serves as a pointer to the first elem of this array. 单词str用作此数组的第一个元素的指针。 So, if you do like this: 因此,如果您这样做:

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. 您可以通过打印出str的地址来进行验证。 In both cases it will be same. 在两种情况下都是一样的。

Now in case of JavaScript string is a primitive type. 现在,在JavaScript的情况下,字符串是原始类型。 All operations on string are done by value instead of by reference. 对字符串的所有操作都是通过值而不是引用来完成的。 So, doing this will produce true. 因此,这样做将产生真实的效果。

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. 字符串的初始化要求缓冲区适合“ foo”,并将名称str1绑定到该缓冲区。 What makes them immutable is that you can't change that buffer. 使它们不可变的原因是您无法更改该缓冲区。 So, you can't do this: 因此,您不能执行以下操作:

str1[0] = 'G'

Executing this command will produce no warning or error in non-strict mode but, it will not change the str1. 在非严格模式下执行此命令不会产生警告或错误,但是不会更改str1。 You can verify it by 您可以通过以下方式进行验证

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. 您实际上正在做的是要一个新的缓冲区以适合“ goo”并将标识符str1绑定到该缓冲区。 No change in that old buffer containing "foo". 包含“ foo”的旧缓冲区没有变化。

So, what happens to "foo"? 那么,“ foo”会怎样?

Java Script has an automatic garbage collector. Java Script具有自动垃圾回收器。 When it sees some chunk of memory that no longer can be referenced by any identifier or ... then it consider that memory free. 当它看到不再可以由任何标识符或...引用的某些内存块时,则认为该内存可用。

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. JavaScript会使用String类创建一个新对象并在string上调用方法。 As soon as the function call returns, the object is destroyed. 一旦函数调用返回,对象就会被销毁。 The below code explains it further: 以下代码进一步解释了它:

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. 结论:在C中,在单个作用域中,变量名用作指针。 So, int, float, string all are mutable. 因此,int,float,string都是可变的。 But in Java Script a primitive type variable name serves as value not as reference 但是在Java Script中,原始类型变量名称用作值,而不是引用

References: C++ primer plus, Java Script The Definitive Guide, C by Stephen Kochan 参考:C ++入门指南,Java脚本权威指南,Stephen Kochan的C

You are correct. 你是对的。 Strings (and numbers) are immutable in java script (and many other languages). 字符串(和数字)在Java脚本(和许多其他语言)中是不可变的。 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. 当“更改变量的值”时,您更改的是变量引用的字符串(或其他内容),而不是值本身。

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 

Let's understand here, first,在这里先了解一下,

let firstString = "Tap";

console.log(firstString);  //Output: Tap 

firstString[0] = "N";

console.log(firstString)   //Output: Tap

This is where we can see the immutable effect !这就是我们可以看到不可变效果的地方

Immutability in this definition is historic.这个定义中的不变性是历史性的。 It's attached to what could be done in OTHER programming languages.它附属于可以用其他编程语言完成的工作。

I think that is the first thing to understand.我认为这是首先要理解的。 And to programmers who have only used JavaScript the question may seem nonsensical or needlessly pedantic.对于只使用过 JavaScript 的程序员来说,这个问题可能看起来很荒谬或不必要的迂腐。 Describing primitives as immutable is like describing ice cream as not being able to jump.将原语描述为不可变就像将冰淇淋描述为不能跳跃一样。 Why would I think it could?为什么我觉得可以? It is only in relation to other historic programming languages that the lack of mutability is apparent when dealing with primitive types.只有与其他历史编程语言相比,在处理原始类型时才会明显缺乏可变性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM