在js引擎中对变量的存储主要有两种位置——栈内存(stack)和堆内存(heap)。
基本数据类型(Number、String 、Boolean、Null和Undefined)存储在栈中,按值访问
引用数据类型(Object 、Array 、Function等)的具体内容存储在堆中,其在堆内存中的引用地址(指针)存储在栈中,按引用访问(访问引用类型的数据时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据)
栈内存为线性有序存储,占据固定大小的空间,自动分配内存空间,会自动释放。容量小,系统分配效率高,垃圾回收快(变量基本上用完就回收了)。
堆内存为动态分配,大小不定也不会自动释放,容量大,系统分配效率相对较低(堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中),垃圾回收慢(堆内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收)。
浅拷贝
发生在栈中的拷贝行为,只拷贝基本值和引用值的地址。
如 =
优点:对于体量巨大的数据可以节省复制的时间和空间
缺点:数据会相互影响,不安全
深拷贝
拷贝栈中基本值和引用值的地址的同时,拷贝地址指向堆中的对象。
优点:数据互不影响,更加安全
缺点:会耗费更多的时间和空间
简单对象的深拷贝
var b = JSON.parse(JSON.stringify(a));
这种方法操作的对象的属性值不能是 undefined、symbol、函数、日期和正则。
最靠谱的深拷贝(推荐)
优点:能够实现对象和数组的深拷贝
缺点:如果拷贝的对象嵌套过深的话,会对性能有一定的消耗
function deepCopy(obj) { var newobj = obj.constructor === Array ? [] : {}; if (typeof obj !== 'object') { return obj; } else { for (var i in obj) { if (typeof obj[i] === 'object'){ //判断对象的这条属性是否为对象 newobj[i] = deepCopy(obj[i]); //若是对象进行嵌套调用 }else{ newobj[i] = obj[i]; } } } return newobj; //返回深度克隆后的对象 } var obj1 = { name: 'shen', show: function (argument) { console.log(1) } } var obj2 = deepCopy(obj1)
有局限性的深拷贝
适用于无嵌套的对象,如下存在嵌套的对象不能使用
var obj2 = { innner: { name: 'shen' } }
es6解构赋值
var obj1 = { name: 'shen', show: function (argument) { console.log(1) } } var obj2 = { ...obj1 }
Object.assign()
var obj1 = { name: 'shen', show: function (argument) { console.log(1) } } var obj2 = Object.assign(obj1)
数组中的slice() 和 concat()
var arr1 = [1,2,3] var arr2 = arr1.slice() // 方法一 // var arr2 = arr1.concat() //方法二