JSON.parse(JSON.stringify(obj))

1,155 阅读2分钟

摘选

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)];
    }