1.浅克隆:只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用。
2.深克隆:是在引用类型的类中也实现了clone,是clone的嵌套,复制后的对象与原对象之间完全不会影响。
各种克隆方式的比较点:
-
是否能克隆所有类型的属性值
-
深克隆还是浅克隆
-
是否能克隆原型(继承)属性
var d = { dd: 1 } var obj = { a: 1, b: "qwe", c: function name(params) {
}, d:d }
obj.proto.e= 222 obj.proto.f= {dd: 123}
// 看看能不能把上面的都克隆到
浅克隆
1. Object.assign()
Object.assign() 方法将所有可枚举(Object.propertyIsEnumerable() 返回 true)和自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。
例子1
var obj = {name: 'jack', age: '18'};
var newObj = Object.assign({}, obj);
例子2
let obj1 = {
name: 'zhang',
age: 10,
friends: ['1',2,23]
}
let obj2 = Object.assign({}, obj1) // 第一个参数利用一个空对象
obj1.friends.push('4')
console.log(obj2)
//{ name: 'zhang', age: 10, friends: [ '1', 2, 23, '4' ] }
不过,采用这种方法克隆,只能克隆原始对象自有属性,不能克隆它原型属性(所继承的值)。如果想要保持继承链,可以采用下面的代码Object.creat()。
利用Obejct.create()和Obejct.assign()实现克隆原型属性
function clone(origin) {
var originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
var obj = {name: 'jack', age: '18'};
obj.__proto__.e= 222
var newObj = clone(obj);
2.扩展运算符号
对象的扩展符号...
-
可以实现浅克隆
-
可以克隆原型属性
let a = {hello:'world'} let obj = {name:'zhang',age:12,plus:a} let obj2 = {...obj}
obj.name = 'wang' obj.plus.hello = 'hello'
console.log(obj); // { name: 'wang', age: 12, plus: { hello: 'hello' } } console.log(obj2); // { name: 'zhang', age: 12, plus: { hello: 'hello' } }
数组也可以使用 var arr = [1,2,3,4,5]; // 写法一: var newObj = [...arr];
// 写法二: var [...newObj] = arr;
3.数组 Array.from()和arr.concat()
可以用ES6提供新方法Array.from()复制数组,此方法复制为浅拷贝
let newArr = Array.from(goalArr)
// Array.from() 和 Array.map() 差不多
let newArr = [].concat(goalArr)
4.浅克隆函数
function cloneObj(obj) {
if (typeof obj !== 'object') {
return obj;
}else {
var newobj = obj.constructor === Array ? [] : {};
for (var i in obj) {
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
}
return newobj;
}
}
深克隆
1.代码原理
/* 深度克隆,断开引用 */
const deepClone = function(obj) {
// 先检测是不是数组和Object
// let isArr = Object.prototype.toString.call(obj) === '[object Array]';
let isArr = Array.isArray(obj);
let isJson = Object.prototype.toString.call(obj) === '[object Object]';
if (isArr) {
// 克隆数组
let newObj = [];
for (let i = 0; i < obj.length; i++) {
newObj[i] = deepClone(obj[i]);
}
return newObj;
} else if (isJson) {
// 克隆Object
let newObj = {};
for (let i in obj) {
newObj[i] = deepClone(obj[i]);
}
return newObj;
}
// 不是引用类型直接返回
return obj;
};
2.第三方库lodash
import _ from 'lodash'
let goal = _.cloneDeep(obj)
3.JSON.parse(JSON.stringify(obj))
-
会忽略
undefined -
会忽略
symbol -
会忽略function,不会报错,不能序列化函数
-
不能解决循环引用的对象
-
可以解析有引用的数据
-
可以深克隆纯数据引入、自有属性
-
不会克隆原型属性
let obj = { name: 'zhangsan', friends: ['lisi', 'baoqiang', 'dada'] } let obj3 = obj let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj3, 'obj3') obj3.name = 'zhangsi' console.log(obj, 'obj') console.log(obj3, 'obj3') console.log(obj2, 'obj2')
// 变量定义的引用类型也可以 let a = { hello: '123' } let obj = { name: 'zhangsan', friends: ['lisi', 'baoqiang', 'dada'], haha:a }
let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj2); /** 输出 { name: 'zhangsan', friends: [ 'lisi', 'baoqiang', 'dada' ], haha: { hello: '123' } } */