不可变性
var a = 'test';
a.slice(1)
a.substr(1)
console.log(a); // test
当我们调用一些字符串的方法对其进行处理时,都不会修改原始的值,而是生成一个新的字符串。
在赋值的时候,看起来,它是被“改变了”
var a= 'test';
a += 'aa';
console.log(a); // 'testaa'
上述的结果,可能会让你误以为其字符串a
是被改变了。但其实不然,这里我们需要引用到内存空间
的概念。
内存空间分为两种:堆内存和栈内存
栈内存:存储的值大小是固定的;空间较小;可以直接操作其保存的变量,运行效率高;由系统(编译器)来分配其内存空间大小;先进后出。
堆内存:存储的值大小不定,可动态调整;空间较大,运行效率低;无法直接操作内部存储,使用引用地址读取;人为/代码分配其内存空间大小。
当我们执行a += 'aa';
的时候,实际是在栈内存中又开辟了一块空间,用于存储testaa
,然后将变量a
指向该空间。所以其原来的test
值仍没有改变。
基本类型的值是存在栈内存
中。存储了变量的标识和对应的值。赋值时,会把对应的标识符和值一起添加到栈内存中。
var a, b;
a = "zyj";
b = a;
console.log(a); // zyj
console.log(b); // zyj
a = "呵呵"; // 改变 a 的值,并不影响 b 的值
console.log(a); // 呵呵
console.log(b); // zyj
基本类型的比较是值和类型的比较
var str1 = "a";
var str2 = "a";
str1 === str2; // true
可变性
我们可以通过一些方法轻易的改变其引用类型。拿数组举例:
const list = [1, 2, 3];
list.push(4); // list [1,2,3,4]
list.pop();
list.splice(1,1)
在存储应用类型是。其存储方式为:栈内存
中保存变量标识符和指向堆内存
一个固定长度的地址。堆内存
中存储的是对象具体的值。
var obj = {
name: 'kerwin'
}
赋值时,在栈内存中会保存其标识符和指向堆内存中的指针,同时将其指针指向堆内存中的地址。JavaScript 是无法直接访问堆内存中的值的。
var obj1 = {
name: 'kerwin'
};
var obj2 = obj1;
可以发现其引用类型的赋值,实际会复制栈中存储的变量和存储地址,指向的是堆中的同一个对象。这也引起了另一个对象的深拷贝和浅拷贝
的问题。
2.引用类型的比较是其对引用的比较,比较两个对象在堆内存中的引用地址是否相同。
在下面的例子中,两个对象的值是相等的,但他们存储在不同的存储空间中。所以其不想等
var obj1 = {name: 'kerwin'};
var obj2 = {name: 'kerwin'};
obj1 === obj2; // false