堆和栈的区别
其实深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同。
堆和栈都是内存中划分出来用来存储的区域。
栈(stack)为自动分配的内存空间,它由系统自动释放;而堆(heap)则是动态分配的内存,大小不定也不会自动释放。
JavaScript中的变量类型
(1)、基本类型
JavaScript中的基本类型有五种: null、undefined、boolean、string、number。 变量是按值存放的,存放在栈中的简单数据段,可以直接访问。
(2)、引用类型
引用类型包括对象和数组,其存储在堆当中,而变量是指针,指向堆。 当我们访问的时候,实际上是访问指针,然后指针去寻找对象或数组。
深拷贝与浅拷贝的理解
浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存; 深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。
(1)、深拷贝
先新建一个空对象,内存中新开辟一块地址,把被复制对象的所有可枚举的(注意可枚举的对象)属性方法一一复制过来,注意要用递归来复制子对象里面的所有属性和方法,直到子子…属性为基本数据类型。关键点:开辟新内存、递归复制。
另外一种定义:深拷贝指的是对象属性所引用的对象全部进行新建对象复制,以保证深复制的对象的引用图不包含任何原有对象或对象图上的任何对象,隔离出两个完全不同的对象图。
(2)、浅拷贝
一个对象复制另外一个对象,如果不是深拷贝,就是浅拷贝。 简单地说,浅拷贝就是将一个对象的内存地址的“”编号“”复制给另一个对象。即在真正访问的时候还是会访问到被复制对象。 或者只是深拷贝了第一层的引用类型,而没有拷贝更深层次的应用类型,而是利用复制地址的方式,这也是浅拷贝
基本数据类型的值是不可变的,动态修改了基本数据类型的值,它的原始值也是不会改变的,例如:
var str = "abc";
console.log(str[1]="f"); // f
console.log(str); // abc
在 js 中没有方法是可以改变布尔值和数字的。倒是有很多操作字符串的方法,但是这些方法都是返回一个新的字符串,并没有改变其原有的数据。
所以,记住这一点:基本数据类型值不可变。
基本类型的比较是值的比较,只要它们的值相等就认为他们是相等的,例如:
var a = 1;
var b = 1;
console.log(a === b);//true
// 比较的时候最好使用严格等,因为 == 是会进行类型转换的,比如:
var a = 1;
var b = true;
console.log(a == b);//true
引用类型存放在堆中
引用类型(object)是存放在堆内存中的,变量实际上是一个存放在栈内存的指针,这个指针指向堆内存中的地址。每个空间大小不一样,要根据情况开进行特定的分配,例如。
var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};
引用类型值可变
引用类型是可以直接改变其值的,例如:
var a = [1,2,3];
a[1] = 5;
console.log(a[1]); // 5
引用类型的比较是引用的比较
所以每次我们对 js 中的引用类型进行操作的时候,都是操作其对象的引用(保存在栈内存中的指针),所以比较两个引用类型,是看其的引用是否指向同一个对象。例如:
var a = [1,2,3];
var b = [1,2,3];
console.log(a === b); // false
虽然变量 a 和变量 b 都是表示一个内容为 1,2,3 的数组,但是其在内存中的位置不一样,也就是说变量 a 和变量 b 指向的不是同一个对象,所以他们是不相等的。
传值与传址
了解了基本数据类型与引用类型的区别之后,我们就应该能明白传值与传址的区别了。在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。例如:
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
所以说,基本类型的赋值的两个变量是两个独立相互不影响的变量。
但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。例如:
var a = {}; // a保存了一个空对象的实例
var b = a; // a和b都指向了这个空对象
a.name = 'jozo';
console.log(a.name); // 'jozo'
console.log(b.name); // 'jozo'
b.age = 22;
console.log(b.age);// 22
console.log(a.age);// 22
console.log(a == b);// true