摘选
JSON.parse(JSON.stringify(obj))一般用来实现深拷贝:
1. JSON.parse()将对象序列化(JSON字符串);
2. JSON.string()实现反序列化(还原)js对象
注意一、obj里面有时间对象,则JSON.stringiify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
var test = {
name: 'a',
date: [new Date(1536627600000), new Date(1540047600000)],
}
let b;
b = JSON.parse(JSON.stringify(test))
1. console.log(b)
// b = {
// name: "a",
// data: [
// "2018-09-11T01:00:00.000Z",
// "2018-10-20T15:00:00.000Z"
// ]
// }
(typeof b.date[0]) => string
2. console.log(test)
// test = {
// name: "a",
// data: [
// "Tue Sep 11 2018 09:00:00 GMT+0800 (中国标准时间)",
// "Sat Oct 20 2018 23:00:00 GMT+0800 (中国标准时间)",
// ]
// }
(typeof test.date[0]) => object
注意二、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象
const test = {
name: "a",
date: new RegExp('\w+')
}
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test';
console.error('ddd', test, copyed)
1. console.log(copyed)
// copyed = {
// name: "a",
// data: {}
// }
2. console.log(test)
// test = {
// name: "test",
// data: new RegExp('\w+')
// }
注意三、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
const test = {
name: 'a',
date: function foo(){
console.log('haha')
},
a: undefined
}
const copyed = JSON.parse(JSON.stringify(test))
1. console.log(copyed)
// copyed = {
// name: "a"
// }
2. console.log(test)
// test = {
// name: "test",
// date: function foo(){
// console.log('haha')
// },
// a: undefined
// }
注意四、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
console.log(test)
// test = {
// name: "test",
// date: null // 即 NaN返回null
// }
注意五、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的,则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
function Person(name) {
this.name = name;
// console.log(name)
}
const liai = new Person('liai');
const test = {
name: 'a',
date: liai,
};
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test'
console.log(test, copyed)
1. console.log(copyed)
// copyed = {
// name: "a",
// data: {name: "liai"}
// }
2. console.log(test)
// test = {
// name: "test",
// data: Person{name: "liai"}
// }
注意六、如果对象中存在循环引用的情况也无法正确实现深拷贝;
解决上述情况(实现深克隆)
function deepClone(data) {
const type = this.judgeType(data);
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
// 不再具有下一层次
return data;
}
if (type === 'array') { // eslint-disable-next-line
for (let i = 0, len = data.length; i < len; i++) {
obj.push(this.deepClone(data[i]));
}
} else if (type === 'object') { // 对原型上的方法也拷贝了....
// eslint-disable-next-line
for (const key in data) {
obj[key] = this.deepClone(data[key]);
}
}
return obj;
}
function judgeType(obj) {
// tostring会返回对应不同的标签的构造函数
const toString = Object.prototype.toString;
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object',
};
if (obj instanceof Element) {
return 'element';
}
return map[toString.call(obj)];
}