1.数据类型
数据类型分为基本数据类型(String、Number、Boolean、Null、Undefined、Symbol (es6引入的一种类型) )和引用数据类型(Object、Array、Function)。
基本数据类型的特点:直接存储在栈中
引用数据类型 :它的真实数据存储在堆内存中,栈中存储的只是指针,指向堆中的实体地址
2.浅拷贝和深拷贝(深拷贝针对引用数据类型)
深拷贝只是针对Array和Object这样的引用数据类型.简单来说,浅拷贝只是拷贝了它在栈中存储的指针,它们指向的都是同一个堆内存地址,所以浅拷贝在某些情况下会造成改变数据后导致别的另一份数据也同步被改变的情况,而深拷贝 是直接将堆内存中存储的数据负责制一份,不会有浅拷贝互相影响的问题
2.1概念
浅拷贝:创建一个新对象,保存原始对象属性值精确拷贝,如果属性是基本数据类型,拷贝的是基本数据类型,如果是 引用数据类型,拷贝的是内存地址,并不会占用新的内存,这种情况下只复制指向某个对象的指针,而不是复制对象本身,新旧对象共享同一块内存
深拷贝: 将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,增加了内存,且修改新对象不会影响原对象,新对象与原对象不共享内存
2.2区别
赋值:把一个对象赋值给新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据
浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享一块内存,会互相影响
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象的子对象进行递归拷贝,前后两个对象互不影响
2.3浅拷贝的方法
1.Object.assign()
把任意多个源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
//基本数据类型 不会改变原对象a中的数据
let a={b:1}
let c=Object.assign({},a)
c.b = 4
console.log(c) //{b:4}
console.log(a) //{b:1}
//引用数据类型 共享同一内存,会改变原对象a中的数据
let a={b:{c:1}}
let c=Object.assign({},a)
c.b.c = 2
console.log(c) //{b:{c:2}}
console.log(a) //{b:{c:2}}
- 函数库lodash的_.clone方法
var _ = require(‘lodash’);
var obj2 = _.clone(obj1);
3.展开运算符
同object.assign()功能相同
let obj2 = {…obj1}
4.Array.prototype.concat()
let arr2 = arr1.concat() // 返回新数组,但当数组中嵌套数组对象时为浅拷贝
5.Array.prototype.slice()
let arr2 = arr1.slice() // 返回新数组,但当数组中嵌套数组对象时为浅拷贝
2.4深拷贝的方法 - JSON.parse()和JSON.stringify()
let arr2 = JSON.parse(JSON.stringify(arr1));
缺点是不能处理函数和正则 - 函数库lodash的_.cloneDeep方法
var _ = require(‘lodash’);
var obj2 = _.cloneDeep(obj1);
3.jQuery.extend()方法
$.extend(deepCopy,target,obj1,[objN]) // 第一个参数为true就是深拷贝 - 手写递归实现
function cloneLoop(x) {
const root = {};
// 栈
const loopList = [
{
parent: root,
key: undefined,
data: x,
}
];
while(loopList.length) {
// 深度优先
const node = loopList.pop();
const parent = node.parent;
const key = node.key;
const data = node.data;
// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
let res = parent;
if (typeof key !== 'undefined') {
res = parent[key] = {};
}
for(let k in data) {
if (data.hasOwnProperty(k)) {
if (typeof data[k] === 'object') {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k],
});
} else {
res[k] = data[k];
}
}
}
}
return root;
}