javascript中存储对象都是存地址的。
浅拷贝:浅拷贝是都指向同一块内存区块,浅拷贝共用同一内存地址,你改值我也变。如果拷贝的对象里面的值是一个对象或者数组,它就是浅拷贝,拷贝的知识引用地址。 jquery的extend方法都是浅拷贝,一般的等号赋值也是浅拷贝 。
准确的理解:
上面vue里面的两个写法也是浅拷贝,具体地址为 https://cn.vuejs.org/v2/guide/list.html
深拷贝:深拷贝则是另外开辟了一块区域,深拷贝是互不影响,你改值我也不变。angular里面的 angular.copy 是深拷贝。
下面实例也可以看出这一点:
// 浅拷贝 const a = {t: 1, p: 'gg'}; const b = a; b.t = 3; console.log(a); // {t: 3, p: 'gg'} console.log(b); // {t: 3, p: 'gg'}
//深拷贝 const c = {t: 1, p: 'gg'}; const d = deepCopy(c); d.t = 3; console.log(c); // {t: 1, p: 'gg'} console.log(d); // {t: 3, p: 'gg'}
//浅拷贝 es6 扩展运算符 let a = [14,12,54,33,22]; let b = a; // 相当于copy a.push(44); console.log(a); // [14, 12, 54, 33, 22, 44] console.log(b); // [14, 12, 54, 33, 22, 44] //深拷贝 let a = [14,12,54,33,22]; let b = [...a]; a.push(44); console.log(a); // [14, 12, 54, 33, 22, 44] console.log(b); // [14, 12, 54, 33, 22]
可以明显看出,浅拷贝在改变其中一个值时,会导致其他也一起改变,而深拷贝不会。
// Cloning an object var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
// Merging objects var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed. console.log(o2);//{b: 2} 源对象没有变 console.log(o3);// {c: 3}
是不是很完美,又可以clone又可以merge。在我这种情况下,我觉得我的代码量又可以减少了,比如:
const defaultOpt = { title: 'hello', name: 'oo', type: 'line' }; // 原来可能需要这样 const opt1 = deepCopy(a); opt1.title = 'opt1'; opt1.type = 'bar'; opt1.extra = 'extra'; // 额外增加配置 // 现在只要这样 const opt2 = Object.assign({}, a, { title: 'opt2', type: 'bar', extra: 'extra' });
注:它只对顶层属性做了赋值,完全没有继续做递归之类的把所有下一层的属性做深拷贝。意思就是是拷贝一层,没有拷贝多层。
一层 { a: 1, b: 2, } 多层 { a: 1, b: 2, c: { d: 4, e: { f: 6, g: 7 } } }
实现深拷贝,遍历key
function deepClone(obj){ //判断obj是否为数组,如果是,初始化数组[],否则初始化对象{} let dcObj = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ //循环 for(key in obj){ //判断对象是否有key属性 if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ dcObj[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 dcObj[key] = obj[key]; } } } } return dcObj; }; let t1 = { "a": 1, "b": 2, "c": { "d": 4, "e": { "f": 6, "g": 7 } } }; let t2=deepClone(t1); t1.a=6; console.log(t1); /* { "a": 6, "b": 2, "c": { "d": 4, "e": { "f": 6, "g": 7 } } } */ console.log(t2); //t1深拷贝给t2, b属性的值还是为2,没有改变,所以是深拷贝 /* { "a": 1, "b": 2, "c": { "d": 4, "e": { "f": 6, "g": 7 } } } */
JavaScript的数据类型
1.基本数据类型
number string boolean null undefined
2.引用数据类型 (简单来说,就是能用new关键字创建的都是引用数据类型)
array(数组) function(函数) regexp(正则) object(对象)
栈与堆
栈(stack) :用来保存简单的数据字段 (先进后出)
堆(heap): 用来保存栈中简单数据字段对指针的引用 (队列优先,先进先出)
*基本数据类型都存在于栈中,引用数据类型存在于堆中(可以这样理解)
*对于原始类型的值而言,其地址和具体内容都存在与栈内存中;而基于引用类型的值,其地址存在栈内存,其具体内容存在堆内存中。
真正的拷贝,就是拷贝过后,arr1和arr2指向的不再是同一片内存地址,而是分别指向各自的地址,这样发生变化的时候就不会出现同时变化,这就是深拷贝。
https://www.jb51.net/article/145470.htm
https://juejin.cn/post/6868166748709847053
https://github.com/zhuanyongxigua/blog/issues/3
参考:https://www.jianshu.com/p/a66050673663
// Deep Clone
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
log(JSON.stringify(obj3));
// { a: 0, b: { c: 0}}