javaScript深浅拷贝
浅拷贝
自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象,但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象。
object.assign
object.assign是ES6中object 的一个方法该方法可以用于 JS 对象的合并等多个用途其中一个用途就是可以进行浅拷贝
object.assign 的语法为:0bject.assign(target,..sources)
let target = {}
let source = {a: {b: 1}}
Object.assign(target,source)
console.log(target)
source.a.b = 10
console.log(source)
console.log(target)
输出:
{ a: { b: 1 } }
{ a: { b: 10 } }
{ a: { b: 10 } }
object.assign 特性
- 它不会拷贝对象的继承属性
- 它不会拷贝对象的不可枚举的属性
- 可以拷贝 Symbol类型的属性
let obj1 = {a: {b: 1}, sym: Symbol(1)}
Object.defineProperty(obj1,"innumerable",{
value:'不可枚举类型',
enumerable: false
})
let obj2 = {}
Object.assign(obj2,obj1)
obj1.a.b = 2
console.log("obj1",obj1)
console.log("obj2",obj2)
扩展运算符 …
/*对象的拷贝 */
let obj = {a: 1, b: {c: 1}}
let obj2 = {...obj}
obj.a = 2
console.log(obj) //{a:2,b:{c:1}} console.log(obj2); //{a:1,b:{c:1}}
obj.b.c = 2
console.log(obj) //{a:2,b:{c:2}} console.log(obj2); //{a:1,b:{c:2}}
/*数组的拷贝 */
let arr = [1, 2, 3]
let newArr = [...arr];//跟arr.slice()是一样的效果
输出
{ a: 2, b: { c: 1 } }
{ a: 2, b: { c: 2 } }
concat 拷贝数组
数组的 concat 方法其实也是浅拷贝
let arr = [1, 2, 3];
let newArr = arr.concat();
newArr[1] = 100
console.log(arr); // [ 1, 2, 3 ]
console.log(newArr);//[1, 100, 3 ]
[ 1, 2, 3 ]
[ 1, 100, 3 ]
slice 拷贝数组
slice 方法仅仅针对数组类型
slice 的语法为:arr.slice(begin,end);
let arr = [1, 2, {val: 4}];
let newArr = arr.slice();
newArr[2].val = 1000;
console.log(arr);//[1,2,{val: 1000 }]
输出
[ 1, 2, { val: 1000 } ]
浅拷贝示例
const shallowClone = (target) => {
if (typeof target === 'object' && target !== null) {
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = target[prop]
return cloneTarget;
} else {
return target
}
}
}
}
浅拷贝总结
浅拷贝只是创建了一个新的对象,复制了原有对象的基本类型的值
对于复杂引用数据类型其在堆内存中完全开辟了一块内存地址并将原有的对象完全复制过来存放
深拷贝
将一个对象从内存中完整地拷贝出来一份给目标对象并从堆内存中开辟一个全新的空间存放新对象,且新对象的修改并不会改变原对象,二者实现真正的分离。
JSON.stringfy
let obj1 = {a: 1, b: [1, 2, 3]}
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log(obj2); //{a:1,b:[1,2,3]}
obj1.a = 2;
obj1.b.push(4);
console.log(obj1); //{a:2,b:[1,2,3,4]}
console.log(obj2); //{a:1,b:[1,2,3]}
输出:
{ a: 1, b: [ 1, 2, 3 ] }
{ a: 2, b: [ 1, 2, 3, 4 ] }
{ a: 1, b: [ 1, 2, 3 ] }
JSON.stringfy 拷贝注意点
1.拷贝的对象的值中如果有函数、undefined、symbol这几种类型,经过JSON.stringify序列化之后的字符串中这个键值对会消失
2.拷贝 Date 引用类型会变成字符串
3.无法拷贝不可枚举的属性
4.无法拷贝对象的原型链
5.拷贝 RegExp 引用类型会变成空对象
6.对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null
7.无法拷贝对象的循环应用,即对象成环(obj[key]=obj)
function Obj() {
this.func = function () {
alert(1)
};
this.obj = {a: 1};
this.arr = [1, 2, 3];
this.und = undefined;
this.reg = /123/;
this.date = new Date(0);
this.NaN = NaN
this.infinity = Infinity;
this.sym = Symbol(1);
}
let obj1 = new Obj();
Object.defineProperty(obj1, 'innumerable', {
enumerable: false,
value: "innumerable"
})
console.log('obj1', obj1)
let str = JSON.stringify(obj1);
let obj2 = JSON.parse(str);
console.log('obj2', obj2)
obj1 Obj {
func: [Function (anonymous)],
obj: { a: 1 },
arr: [ 1, 2, 3 ],
und: undefined,
reg: /123/,
date: 1970-01-01T00:00:00.000Z,
NaN: NaN,
infinity: Infinity,
sym: Symbol(1)
}
obj2 {
obj: { a: 1 },
arr: [ 1, 2, 3 ],
reg: {},
date: '1970-01-01T00:00:00.000Z',
NaN: null,
infinity: null
}