js深拷贝/浅拷贝

数据类型
数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。
  • 基本数据类型的特点:直接存储在栈(stack)中的数据
  • 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
 
浅拷贝与深拷贝
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
深拷贝和浅拷贝的示意图大致如下:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
 
赋值和浅拷贝的区别
赋值:复制引用类型存在栈中的地址
浅拷贝:新建一个引用类型,把原数据的存在栈里的属性值复制到新数据
深拷贝:新建一个引用类型,把原数据的存在堆里的属性值复制到新数据
 

 
浅拷贝的实现方式
//原始数据
var obj = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var arr = [1, "hello", { f: { g: 1 } }];
 
// 检查数据类型
function checkType(target) {
return Object.prototype.toString.call(target).slice(8, -1);
}
 1.Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
var obj1 = Object.assign({},obj);
obj1.a = 222;
console.log(obj.b.f === obj1.b.f, "Object.assign"); // true
console.log(obj.a === obj1.a, "Object.assign"); // false
2.Array.prototype.concat()
var arr1 = arr.concat();
console.log(arr[2].f === arr1[2].f, "Array.prototype.concat"); //true
3.Array.prototype.slice()
var arr2 = arr.slice();
console.log(arr[2].f === arr2[2].f, "Array.prototype.slice"); //true 
4.赋值
function shallowCopy(target) {
let result = {};
for (let i in target) {
if (target.hasOwnProperty(i)) {
result[i] = target[i];
}
}
return result;
}
var obj2 = shallowCopy(obj);
console.log(obj.b.f === obj2.b.f, "hasOwnProperty"); // true

 

根据四种浅拷贝方式,抽象出一个浅拷贝方法
// 浅拷贝
function shallowClone(target) {
let result;
let targetType = checkType(target);
// 判断传入数据类型
if (targetType === "Object") {
result = Object.assign(target);
} else if (targetType === "Array") {
result = target.concat();
} else {
return target;
}
return result;
}
var obj4 = shallowClone(obj);
var arr4 = shallowClone(arr);
console.log(obj.b.f === obj4.b.f, "shallowClone"); // true
console.log(arr[2].f === arr4[2].f, "shallowClone"); // true

 

深拷贝的实现方式
1.递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
function deepClone(target) {
let result;
let targetType = checkType(target);
// 判断传入数据类型
if (targetType === "Object") {
result = {};
} else if (targetType === "Array") {
result = [];
} else {
return target;
}
// 遍历传入目标数据
for (let i in target) {
let value = target[i];
if (checkType(value) === "Object" || checkType(value) === "Array") {
result[i] = deepClone(value);
} else {
result[i] = value;
}
}
return result;
}
var obj3 = deepClone(obj);
var arr3 = deepClone(arr);
console.log(obj.b.f === obj3.b.f, "deepClone"); // false
console.log(arr[2].f === arr3[2].f, "deepClone"); // false
 
2.JSON.parse(JSON.stringify())
var obj5 = JSON.parse(JSON.stringify(obj));
var arr5 = JSON.parse(JSON.stringify(arr));
obj5.d()
console.log(obj.b.f === obj5.b.f, "deepClone"); // false
console.log(arr[2].f === arr5[2].f, "deepClone"); // false
注意:这种方式不可以用于数据里面有函数作为值的数据,因为JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数
 
posted @ 2019-02-19 08:51  半夜盗贼  阅读(302)  评论(0编辑  收藏  举报