写一下这几天在看面试题时又回顾到的一个知识点,深浅拷贝。
这个应该是在ES5面向对象之前写过,现在是忘的差不多了,在梳理了一下逻辑以后,决定重新开篇文章写一下。
一、堆与栈
如果是明白堆与栈的,或者是不屑于理解基础知识,只求深浅拷贝怎么写的,可以跳过这部分直接看后面。但我认为理解一个东西,就要贯彻到底,一知半解多半会出问题。
那我们先说一下堆与栈,什么是堆什么是栈呢。在我们创建变量之初,内存会开辟两类空间,就是栈和堆。当然我们知道,变量有两种类型:基本数据类型(包括ES6的symbol数据)和引用类型数据,所以这两种对象分别储存于这两个空间之中。
这样应该很好理解,那么堆与栈的关系呢?这里就要提到一个问题了,在ECMAscript语法中,js是不允许直接访问堆内存的,那么我们要如何取出引用类数据呢,这就要提到地址了。每个引用类数据,都有对应的地址(地址不唯一),每个地址都能指向对应的堆数据。举个例子:
let demo = {id:"xiaoming"}
那么这行代码中,{id:"xiaoming"}就会储存于内存开辟的堆空间中,而demo就会作为地址的变量名存放于栈内存中。如果还没看懂,我画个图,作为对比我再新建几个变量:
let demo = {id:"xiaoming"};
let a = 'hello';
let b = 123
通过上述图示,应该就能很清楚的展示基本数据类型和引用数据类型的存储区别了,这里再附上一段比较代码,大家参考一下,应该会更加清楚:
var str1 = new String('abc');
var str2='abc';
alert(str1==str2);// true
alert(str1===str2);// false
最后总结一下:
1.在代码运行的时候,每个线程会分配一个堆和一个栈。堆的大小是不固定的,可以随时增加;而栈创建的时候就确定大小,所以可能溢出。
2.堆的空间大,但是运行效率相对较低;而栈相反。
3.栈存放基本类型数据,函数,对象指针等;堆存放对象;
二、递归
同上,只想看深浅拷贝代码的可以跳过了。但这里我还是建议看一下的。
简单来说,递归是一种函数编码思想。用法就是在函数内调用自身,同时为其中增加一个条件来终止代码(不然会无限循环)。举个例子:
var num = 0;
function foo2(){
num ++
console.log("当前的num值:"+num);
if(num > 5){
// 终止代码的执行
return ;
}
foo2();
}
foo2();
递归是一种理解起来并不难,但实际操作时却需要想半天的东西,只能多写来提高熟练度了。
三、浅拷贝
所谓拷贝,说穿了就是数据的复制,但在js中因为我前面提到的堆和栈的问题,我们如果只是简单的循环,仅仅只能对浅层的数据进行复制,这就是浅拷贝,那么在不涉及嵌套对象的前提下,就对仅仅是基本数据类型的对象进行拷贝。
懒人版浅拷贝方法一
此方法是ES6中提供的,但注意,该方法不会拷贝不可枚举的属性和继承属性。
object.assign
let demo = {};
let test = {
name:'aaa',
age:123
}
Object.assign(demo,test);
console.log(demo);
这里多一嘴:这种方式不止ES6,在jq中也有提供$.extend()方法,效果是一样的。
懒人版浅拷贝方法二
同样是在ES6中,由语法糖提供的扩展运算符,这个就更简单了。。
demo = {...test}
console.log(demo);
懒人版浅拷贝方法三
看了上面的,觉得浅拷贝真的很简单吧,这里再说一下,同样可以用slice,concat等对数组进行操作(注意splice方法,该方法会对原数组进行切剪)
js原生代码的浅拷贝
function simpleCopy(data) {
// 新地址, 判断data是数组,还是对象
var newData = Array.isArray(data)? [] : {}
// 循环data ,然后复制数据
for(var key in data){
// 复制
newData[key] = data[key]
}
// 返回复制完成的数据集合
return newData;
}
四、深拷贝
终于到深拷贝了,那么先说一下,深拷贝就不止是对浅层数据的拷贝了,我们要结合上面的堆栈和递归思想,实现原有对象的完全复制。二者实现真正的分离。
懒人版深拷贝方法一
ok,那么按照顺序先放一个懒人版的,我们可以通过JSON来实现深浅拷贝(应该是目前最简单的深浅拷贝了)。
递归深拷贝
这里提出三个问题,有待解决:
1.关于不可枚举的属性以及symbol类型数据的复制
2.Date,RegExp类型
3.关于数据循环引用的问题?
我写了一段,但是没有完全解决,带我搞定了上传代码